egui_glow/
shader_version.rs

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