-
-
Notifications
You must be signed in to change notification settings - Fork 130
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
165: expose webgl extensions through parameter api r=grovesNL a=Frizi Currently it is impossible to query for webgl extensions, due to it using specialized unexposed api for retreiving the list. This PR exposes the list with desktop gl api by intercepting parameter calls and implementing them using the web-specific api under the hood. Co-authored-by: Frizi <frizi09@gmail.com>
- Loading branch information
Showing
4 changed files
with
269 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,216 @@ | ||
/// A version number for a specific component of an OpenGL implementation | ||
#[derive(Clone, Eq, Ord, PartialEq, PartialOrd)] | ||
pub(crate) struct Version { | ||
pub major: u32, | ||
pub minor: u32, | ||
pub is_embedded: bool, | ||
pub revision: Option<u32>, | ||
pub vendor_info: String, | ||
} | ||
|
||
impl Version { | ||
/// Create a new OpenGL version number | ||
pub fn new(major: u32, minor: u32, revision: Option<u32>, vendor_info: String) -> Self { | ||
Version { | ||
major: major, | ||
minor: minor, | ||
is_embedded: false, | ||
revision: revision, | ||
vendor_info, | ||
} | ||
} | ||
/// Create a new OpenGL ES version number | ||
pub fn new_embedded(major: u32, minor: u32, vendor_info: String) -> Self { | ||
Version { | ||
major, | ||
minor, | ||
is_embedded: true, | ||
revision: None, | ||
vendor_info, | ||
} | ||
} | ||
|
||
/// Get a tuple of (major, minor) versions | ||
pub fn tuple(&self) -> (u32, u32) { | ||
(self.major, self.minor) | ||
} | ||
|
||
/// According to the OpenGL specification, the version information is | ||
/// expected to follow the following syntax: | ||
/// | ||
/// ~~~bnf | ||
/// <major> ::= <number> | ||
/// <minor> ::= <number> | ||
/// <revision> ::= <number> | ||
/// <vendor-info> ::= <string> | ||
/// <release> ::= <major> "." <minor> ["." <release>] | ||
/// <version> ::= <release> [" " <vendor-info>] | ||
/// ~~~ | ||
/// | ||
/// Note that this function is intentionally lenient in regards to parsing, | ||
/// and will try to recover at least the first two version numbers without | ||
/// resulting in an `Err`. | ||
/// # Notes | ||
/// `WebGL 2` version returned as `OpenGL ES 3.0` | ||
pub fn parse(mut src: &str) -> Result<Version, &str> { | ||
let webgl_sig = "WebGL "; | ||
// According to the WebGL specification | ||
// VERSION WebGL<space>1.0<space><vendor-specific information> | ||
// SHADING_LANGUAGE_VERSION WebGL<space>GLSL<space>ES<space>1.0<space><vendor-specific information> | ||
let is_webgl = src.starts_with(webgl_sig); | ||
let is_es = if is_webgl { | ||
let pos = src.rfind(webgl_sig).unwrap_or(0); | ||
src = &src[pos + webgl_sig.len()..]; | ||
true | ||
} else { | ||
let es_sig = " ES "; | ||
match src.rfind(es_sig) { | ||
Some(pos) => { | ||
src = &src[pos + es_sig.len()..]; | ||
true | ||
} | ||
None => false, | ||
} | ||
}; | ||
|
||
let glsl_es_sig = "GLSL ES "; | ||
let is_glsl = match src.find(glsl_es_sig) { | ||
Some(pos) => { | ||
src = &src[pos + glsl_es_sig.len()..]; | ||
true | ||
} | ||
None => false, | ||
}; | ||
|
||
let (version, vendor_info) = match src.find(' ') { | ||
Some(i) => (&src[..i], src[i + 1..].to_string()), | ||
None => (src, String::new()), | ||
}; | ||
|
||
// TODO: make this even more lenient so that we can also accept | ||
// `<major> "." <minor> [<???>]` | ||
let mut it = version.split('.'); | ||
let major = it.next().and_then(|s| s.parse().ok()); | ||
let minor = it.next().and_then(|s| { | ||
let trimmed = if s.starts_with('0') { | ||
"0" | ||
} else { | ||
s.trim_end_matches('0') | ||
}; | ||
trimmed.parse().ok() | ||
}); | ||
let revision = if is_webgl { | ||
None | ||
} else { | ||
it.next().and_then(|s| s.parse().ok()) | ||
}; | ||
|
||
match (major, minor, revision) { | ||
(Some(major), Some(minor), revision) => Ok(Version { | ||
// Return WebGL 2.0 version as OpenGL ES 3.0 | ||
major: if is_webgl && !is_glsl { | ||
major + 1 | ||
} else { | ||
major | ||
}, | ||
minor, | ||
is_embedded: is_es, | ||
revision, | ||
vendor_info, | ||
}), | ||
(_, _, _) => Err(src), | ||
} | ||
} | ||
} | ||
|
||
impl std::fmt::Debug for Version { | ||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { | ||
match ( | ||
self.major, | ||
self.minor, | ||
self.revision, | ||
self.vendor_info.as_str(), | ||
) { | ||
(major, minor, Some(revision), "") => write!(f, "{}.{}.{}", major, minor, revision), | ||
(major, minor, None, "") => write!(f, "{}.{}", major, minor), | ||
(major, minor, Some(revision), vendor_info) => { | ||
write!(f, "{}.{}.{}, {}", major, minor, revision, vendor_info) | ||
} | ||
(major, minor, None, vendor_info) => write!(f, "{}.{}, {}", major, minor, vendor_info), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::Version; | ||
|
||
#[test] | ||
fn test_version_parse() { | ||
assert_eq!(Version::parse("1"), Err("1")); | ||
assert_eq!(Version::parse("1."), Err("1.")); | ||
assert_eq!(Version::parse("1 h3l1o. W0rld"), Err("1 h3l1o. W0rld")); | ||
assert_eq!(Version::parse("1. h3l1o. W0rld"), Err("1. h3l1o. W0rld")); | ||
assert_eq!( | ||
Version::parse("1.2.3"), | ||
Ok(Version::new(1, 2, Some(3), String::new())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2"), | ||
Ok(Version::new(1, 2, None, String::new())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2 h3l1o. W0rld"), | ||
Ok(Version::new(1, 2, None, "h3l1o. W0rld".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2.h3l1o. W0rld"), | ||
Ok(Version::new(1, 2, None, "W0rld".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2. h3l1o. W0rld"), | ||
Ok(Version::new(1, 2, None, "h3l1o. W0rld".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2.3.h3l1o. W0rld"), | ||
Ok(Version::new(1, 2, Some(3), "W0rld".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("1.2.3 h3l1o. W0rld"), | ||
Ok(Version::new(1, 2, Some(3), "h3l1o. W0rld".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("OpenGL ES 3.1"), | ||
Ok(Version::new_embedded(3, 1, String::new())) | ||
); | ||
assert_eq!( | ||
Version::parse("OpenGL ES 2.0 Google Nexus"), | ||
Ok(Version::new_embedded(2, 0, "Google Nexus".to_string())) | ||
); | ||
assert_eq!( | ||
Version::parse("GLSL ES 1.1"), | ||
Ok(Version::new_embedded(1, 1, String::new())) | ||
); | ||
assert_eq!( | ||
Version::parse("OpenGL ES GLSL ES 3.20"), | ||
Ok(Version::new_embedded(3, 2, String::new())) | ||
); | ||
assert_eq!( | ||
// WebGL 2.0 should parse as OpenGL ES 3.0 | ||
Version::parse("WebGL 2.0 (OpenGL ES 3.0 Chromium)"), | ||
Ok(Version::new_embedded( | ||
3, | ||
0, | ||
"(OpenGL ES 3.0 Chromium)".to_string() | ||
)) | ||
); | ||
assert_eq!( | ||
Version::parse("WebGL GLSL ES 3.00 (OpenGL ES GLSL ES 3.0 Chromium)"), | ||
Ok(Version::new_embedded( | ||
3, | ||
0, | ||
"(OpenGL ES GLSL ES 3.0 Chromium)".to_string() | ||
)) | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters