egl: enumerate supported dmabuf formats

This commit is contained in:
Victor Brekenfeld 2021-04-08 02:07:46 +02:00
parent a74aa728f7
commit 4d8bd26131
1 changed files with 92 additions and 1 deletions

View File

@ -1,5 +1,6 @@
//! Type safe native types for safe egl initialisation //! Type safe native types for safe egl initialisation
use std::collections::HashSet;
use std::sync::Arc; use std::sync::Arc;
use std::ffi::CStr; use std::ffi::CStr;
use std::mem::MaybeUninit; use std::mem::MaybeUninit;
@ -11,7 +12,7 @@ use wayland_server::{protocol::wl_buffer::WlBuffer, Display};
#[cfg(feature = "use_system_lib")] #[cfg(feature = "use_system_lib")]
use wayland_sys::server::wl_display; use wayland_sys::server::wl_display;
use crate::backend::allocator::{Buffer, dmabuf::Dmabuf}; use crate::backend::allocator::{Buffer, dmabuf::Dmabuf, Fourcc, Modifier};
use crate::backend::egl::{ use crate::backend::egl::{
ffi::egl::types::EGLImage, ffi::egl::types::EGLImage,
ffi, wrap_egl_call, EGLError, Error, ffi, wrap_egl_call, EGLError, Error,
@ -54,6 +55,8 @@ pub struct EGLDisplay {
pub(crate) display: Arc<EGLDisplayHandle>, pub(crate) display: Arc<EGLDisplayHandle>,
pub(crate) egl_version: (i32, i32), pub(crate) egl_version: (i32, i32),
pub(crate) extensions: Vec<String>, pub(crate) extensions: Vec<String>,
pub(crate) dmabuf_import_formats: HashSet<(u32, u64)>,
pub(crate) dmabuf_render_formats: HashSet<(u32, u64)>,
surface_type: ffi::EGLint, surface_type: ffi::EGLint,
logger: slog::Logger, logger: slog::Logger,
} }
@ -137,6 +140,9 @@ impl EGLDisplay {
}; };
info!(log, "Supported EGL display extensions: {:?}", extensions); info!(log, "Supported EGL display extensions: {:?}", extensions);
let (dmabuf_import_formats, dmabuf_render_formats) =
get_dmabuf_formats(&display, &extensions, &log).map_err(Error::DisplayCreationError)?;
// egl <= 1.2 does not support OpenGL ES (maybe we want to support OpenGL in the future?) // egl <= 1.2 does not support OpenGL ES (maybe we want to support OpenGL in the future?)
if egl_version <= (1, 2) { if egl_version <= (1, 2) {
return Err(Error::OpenGlesNotSupported(None)); return Err(Error::OpenGlesNotSupported(None));
@ -149,6 +155,8 @@ impl EGLDisplay {
surface_type: native.surface_type(), surface_type: native.surface_type(),
egl_version, egl_version,
extensions, extensions,
dmabuf_import_formats,
dmabuf_render_formats,
logger: log, logger: log,
}) })
} }
@ -456,6 +464,89 @@ impl EGLDisplay {
} }
} }
fn get_dmabuf_formats(display: &ffi::egl::types::EGLDisplay, extensions: &[String], log: &::slog::Logger) -> Result<(HashSet<(u32, u64)>, HashSet<(u32, u64)>), EGLError>
{
use std::convert::TryFrom;
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import") {
warn!(log, "Dmabuf import extension not available");
return Ok((HashSet::new(), HashSet::new()));
}
let formats = {
// when we only have the image_dmabuf_import extension we can't query
// which formats are supported. These two are on almost always
// supported; it's the intended way to just try to create buffers.
// Just a guess but better than not supporting dmabufs at all,
// given that the modifiers extension isn't supported everywhere.
if !extensions.iter().any(|s| s == "EGL_EXT_image_dma_buf_import_modifiers") {
vec![
Fourcc::Argb8888 as u32,
Fourcc::Xrgb8888 as u32,
]
} else {
let mut num = 0i32;
wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufFormatsEXT(*display, 0, std::ptr::null_mut(), &mut num as *mut _)
})?;
if num == 0 {
return Ok((HashSet::new(), HashSet::new()));
}
let mut formats: Vec<u32> = Vec::with_capacity(num as usize);
wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufFormatsEXT(*display, num, formats.as_mut_ptr() as *mut _, &mut num as *mut _)
})?;
unsafe {
formats.set_len(num as usize);
}
formats
}
};
let mut texture_formats = HashSet::new();
let mut render_formats = HashSet::new();
for format in formats {
let mut num = 0i32;
wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufModifiersEXT(*display, format as i32, 0, std::ptr::null_mut(), std::ptr::null_mut(), &mut num as *mut _)
})?;
if num == 0 {
texture_formats.insert((format, Modifier::Invalid.into()));
render_formats.insert((format, Modifier::Invalid.into()));
} else {
let mut mods: Vec<u64> = Vec::with_capacity(num as usize);
let mut external: Vec<ffi::egl::types::EGLBoolean> = Vec::with_capacity(num as usize);
wrap_egl_call(|| unsafe {
ffi::egl::QueryDmaBufModifiersEXT(*display, format as i32, num, mods.as_mut_ptr(), external.as_mut_ptr(), &mut num as *mut _)
})?;
unsafe {
mods.set_len(num as usize);
external.set_len(num as usize);
}
for (modifier, external_only) in mods.into_iter().zip(external.into_iter()) {
texture_formats.insert((format, modifier));
if external_only == 0 {
render_formats.insert((format, modifier));
}
}
}
}
info!(log, "Supported dmabuf import formats: {:#?}",
texture_formats.clone().into_iter()
.map(|(fmt, modi)| (Fourcc::try_from(fmt), Modifier::from(modi))).collect::<Vec<_>>());
info!(log, "Supported dmabuf render formats: {:#?}",
render_formats.clone().into_iter()
.map(|(fmt, modi)| (Fourcc::try_from(fmt), Modifier::from(modi))).collect::<Vec<_>>());
Ok((texture_formats, render_formats))
}
/// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s. /// Type to receive [`EGLImages`] for EGL-based [`WlBuffer`]s.
/// ///
/// Can be created by using [`EGLGraphicsBackend::bind_wl_display`]. /// Can be created by using [`EGLGraphicsBackend::bind_wl_display`].