egui_glow/
shader_version.rs

1#![allow(unsafe_code)]
2#![allow(clippy::undocumented_unsafe_blocks)]
3
4use std::convert::TryInto;
5
6/// Helper for parsing and interpreting the OpenGL shader version.
7#[derive(Copy, Clone, Debug, PartialEq, Eq)]
8#[allow(dead_code)]
9pub enum ShaderVersion {
10    Gl120,
11
12    /// OpenGL 1.4 or later
13    Gl140,
14
15    /// e.g. WebGL1
16    Es100,
17
18    /// e.g. WebGL2
19    Es300,
20}
21
22impl ShaderVersion {
23    pub fn get(gl: &glow::Context) -> Self {
24        use glow::HasContext as _;
25        let shading_lang_string =
26            unsafe { gl.get_parameter_string(glow::SHADING_LANGUAGE_VERSION) };
27        let shader_version = Self::parse(&shading_lang_string);
28        log::debug!(
29            "Shader version: {:?} ({:?}).",
30            shader_version,
31            shading_lang_string
32        );
33        shader_version
34    }
35
36    #[inline]
37    pub(crate) fn parse(glsl_ver: &str) -> Self {
38        let start = glsl_ver.find(|c| char::is_ascii_digit(&c)).unwrap();
39        let es = glsl_ver[..start].contains(" ES ");
40        let ver = glsl_ver[start..]
41            .split_once(' ')
42            .map_or(&glsl_ver[start..], |x| x.0);
43        let [maj, min]: [u8; 2] = ver
44            .splitn(3, '.')
45            .take(2)
46            .map(|x| x.parse().unwrap_or_default())
47            .collect::<Vec<u8>>()
48            .try_into()
49            .unwrap();
50        if es {
51            if maj >= 3 {
52                Self::Es300
53            } else {
54                Self::Es100
55            }
56        } else if maj > 1 || (maj == 1 && min >= 40) {
57            Self::Gl140
58        } else {
59            Self::Gl120
60        }
61    }
62
63    /// Goes on top of the shader.
64    pub fn version_declaration(&self) -> &'static str {
65        match self {
66            Self::Gl120 => "#version 120\n",
67            Self::Gl140 => "#version 140\n",
68            Self::Es100 => "#version 100\n",
69            Self::Es300 => "#version 300 es\n",
70        }
71    }
72
73    /// If true, use `in/out`. If `false`, use `varying` and `gl_FragColor`.
74    pub fn is_new_shader_interface(&self) -> bool {
75        match self {
76            Self::Gl120 | Self::Es100 => false,
77            Self::Es300 | Self::Gl140 => true,
78        }
79    }
80
81    pub fn is_embedded(&self) -> bool {
82        match self {
83            Self::Gl120 | Self::Gl140 => false,
84            Self::Es100 | Self::Es300 => true,
85        }
86    }
87}
88
89#[test]
90fn test_shader_version() {
91    use ShaderVersion::{Es100, Es300, Gl120, Gl140};
92    for (s, v) in [
93        ("1.2 OpenGL foo bar", Gl120),
94        ("3.0", Gl140),
95        ("0.0", Gl120),
96        ("OpenGL ES GLSL 3.00 (WebGL2)", Es300),
97        ("OpenGL ES GLSL 1.00 (WebGL)", Es100),
98        ("OpenGL ES GLSL ES 1.00 foo bar", Es100),
99        ("WebGL GLSL ES 3.00 foo bar", Es300),
100        ("WebGL GLSL ES 3.00", Es300),
101        ("WebGL GLSL ES 1.0 foo bar", Es100),
102    ] {
103        assert_eq!(ShaderVersion::parse(s), v);
104    }
105}