diff --git a/Cargo.toml b/Cargo.toml index ff58ddd..b9c2aed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ wayland-server = { version = "0.28.3", optional = true } wayland-sys = { version = "0.28", optional = true } winit = { version = "0.24.0", optional = true } xkbcommon = "0.4.0" +scan_fmt = "0.2" [dev-dependencies] slog-term = "2.3" diff --git a/src/backend/renderer/gles2/mod.rs b/src/backend/renderer/gles2/mod.rs index bece9f3..2e77ed8 100644 --- a/src/backend/renderer/gles2/mod.rs +++ b/src/backend/renderer/gles2/mod.rs @@ -10,10 +10,13 @@ use std::sync::{ mpsc::{channel, Receiver, Sender}, }; use std::{collections::HashSet, os::raw::c_char}; +use std::convert::TryFrom; use cgmath::{prelude::*, Matrix3}; mod shaders; +mod version; + use super::{Bind, Renderer, Texture, Transform, Unbind}; use crate::backend::allocator::{ dmabuf::{Dmabuf, WeakDmabuf}, @@ -331,6 +334,11 @@ impl Gles2Renderer { ); info!(log, "Supported GL Extensions: {:?}", exts); + let gl_version = version::GlVersion::try_from(&gl).unwrap_or_else(|_| { + warn!(log, "Failed to detect GLES version, defaulting to 2.0"); + version::GLES_2_0 + }); + // required for the manditory wl_shm formats if !exts.iter().any(|ext| ext == "GL_EXT_texture_format_BGRA8888") { return Err(Gles2Error::GLExtensionNotSupported(&[ @@ -338,7 +346,7 @@ impl Gles2Renderer { ])); } // required for buffers without linear memory layout - if !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") { + if gl_version < version::GLES_3_0 && !exts.iter().any(|ext| ext == "GL_EXT_unpack_subimage") { return Err(Gles2Error::GLExtensionNotSupported(&["GL_EXT_unpack_subimage"])); } diff --git a/src/backend/renderer/gles2/version.rs b/src/backend/renderer/gles2/version.rs new file mode 100644 index 0000000..64f5bbc --- /dev/null +++ b/src/backend/renderer/gles2/version.rs @@ -0,0 +1,94 @@ +use std::{convert::TryFrom, ffi::CStr, os::raw::c_char}; + +use scan_fmt::scan_fmt; + +use super::ffi::{self, Gles2}; + +pub const GLES_3_0: GlVersion = GlVersion::new(3, 0); +pub const GLES_2_0: GlVersion = GlVersion::new(2, 0); + +#[derive(Debug, PartialEq, Clone, Copy)] +pub struct GlVersion { + pub major: i32, + pub minor: i32, +} + +impl GlVersion { + pub const fn new(major: i32, minor: i32) -> Self { + GlVersion { major, minor } + } +} + +impl Eq for GlVersion {} + +impl Ord for GlVersion { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + match self.major.cmp(&other.major) { + std::cmp::Ordering::Equal => self.minor.cmp(&other.minor), + ord => ord, + } + } +} + +impl PartialOrd for GlVersion { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl TryFrom<&CStr> for GlVersion { + type Error = scan_fmt::parse::ScanError; + + fn try_from(value: &CStr) -> Result { + scan_fmt!(&value.to_string_lossy(), "{d}.{d}", i32, i32) + .or_else(|_| scan_fmt!(&value.to_string_lossy(), "OpenGL ES {d}.{d}", i32, i32)) + .map(|(major, minor)| GlVersion::new(major, minor)) + } +} + +impl TryFrom<&Gles2> for GlVersion { + type Error = scan_fmt::parse::ScanError; + + fn try_from(value: &Gles2) -> Result { + let version = unsafe { CStr::from_ptr(value.GetString(ffi::VERSION) as *const c_char) }; + GlVersion::try_from(version) + } +} + +#[cfg(test)] +mod tests { + use super::GlVersion; + use std::{convert::TryFrom, ffi::CStr, os::raw::c_char}; + + #[test] + fn test_parse_mesa_3_2() { + let gl_version = "OpenGL ES 3.2 Mesa 20.3.5"; + let gl_version_str = unsafe { CStr::from_ptr(gl_version.as_ptr() as *const c_char) }; + assert_eq!(GlVersion::try_from(gl_version_str), Ok(GlVersion::new(3, 2))) + } + + #[test] + fn test_3_2_greater_3_0() { + assert!(GlVersion::new(3,2) > GlVersion::new(3,0)) + } + + #[test] + fn test_3_0_greater_or_equal_3_0() { + assert!(GlVersion::new(3,0) >= GlVersion::new(3,0)) + } + + #[test] + fn test_3_0_less_or_equal_3_0() { + assert!(GlVersion::new(3,0) <= GlVersion::new(3,0)) + } + + #[test] + fn test_3_0_eq_3_0() { + assert!(GlVersion::new(3,0) == GlVersion::new(3,0)) + } + + #[test] + fn test_2_0_less_3_0() { + assert!(GlVersion::new(2,0) < GlVersion::new(3,0)) + } +}