1
0
Fork 0
forked from wry/wry

metal: use IN_FORMATS plane property

This commit is contained in:
Julian Orth 2023-10-29 16:58:16 +01:00
parent d022d96fbf
commit e0ed29038e
9 changed files with 183 additions and 87 deletions

View file

@ -35,8 +35,11 @@ use crate::{
utils::{buf::Buf, errorfmt::ErrorFmt, stack::Stack, syncqueue::SyncQueue, vec_ext::VecExt},
video::{
dmabuf::DmaBuf,
drm::sys::{get_version, DRM_CAP_CURSOR_HEIGHT, DRM_CAP_CURSOR_WIDTH},
INVALID_MODIFIER,
drm::sys::{
drm_format_modifier, drm_format_modifier_blob, get_version, DRM_CAP_CURSOR_HEIGHT,
DRM_CAP_CURSOR_WIDTH, FORMAT_BLOB_CURRENT,
},
Modifier, INVALID_MODIFIER,
},
};
pub use sys::{
@ -106,6 +109,8 @@ pub enum DrmError {
InvalidRead,
#[error("Could not determine the drm version")]
Version(#[source] OsError),
#[error("Format of IN_FORMATS property is invalid")]
InFormats,
}
fn render_node_name(fd: c::c_int) -> Result<Ustring, DrmError> {
@ -174,6 +179,11 @@ impl Drm {
}
}
pub struct InFormat {
pub format: u32,
pub modifiers: Vec<Modifier>,
}
pub struct DrmMaster {
drm: Drm,
u32_bufs: Stack<Vec<u32>>,
@ -373,6 +383,64 @@ impl DrmMaster {
}
}
pub fn get_in_formats(&self, property: u32) -> Result<Vec<InFormat>, DrmError> {
let blob = self.getblob_vec::<u8>(DrmBlob(property))?;
let header: drm_format_modifier_blob = match uapi::pod_read_init(blob.as_bytes()) {
Ok(h) => h,
Err(_) => {
log::error!("Header of IN_FORMATS blob doesn't fit in the blob");
return Err(DrmError::InFormats);
}
};
if header.version != FORMAT_BLOB_CURRENT {
log::error!(
"Header of IN_FORMATS has an invalid version: {}",
header.version
);
return Err(DrmError::InFormats);
}
let formats_start = header.formats_offset as usize;
let formats_end = formats_start
.wrapping_add((header.count_formats as usize).wrapping_mul(mem::size_of::<u32>()));
let modifiers_start = header.modifiers_offset as usize;
let modifiers_end = modifiers_start.wrapping_add(
(header.count_modifiers as usize).wrapping_mul(mem::size_of::<drm_format_modifier>()),
);
if blob.len() < formats_end || formats_end < formats_start {
log::error!("Formats of IN_FORMATS blob don't fit in the blob");
return Err(DrmError::InFormats);
}
if blob.len() < modifiers_end || modifiers_end < modifiers_start {
log::error!("Formats of IN_FORMATS blob don't fit in the blob");
return Err(DrmError::InFormats);
}
let mut formats: Vec<_> = uapi::pod_iter::<u32, _>(&blob[formats_start..formats_end])
.unwrap()
.map(|f| InFormat {
format: f,
modifiers: vec![],
})
.collect();
let modifiers =
uapi::pod_iter::<drm_format_modifier, _>(&blob[modifiers_start..modifiers_end])
.unwrap();
for modifier in modifiers {
let offset = modifier.offset as usize;
let mut indices = modifier.formats;
while indices != 0 {
let idx = indices.trailing_zeros();
indices &= !(1 << idx);
let idx = idx as usize + offset;
if idx >= formats.len() {
log::error!("Modifier offset is out of bounds");
return Err(DrmError::InFormats);
}
formats[idx].modifiers.push(modifier.modifier);
}
}
Ok(formats)
}
#[allow(clippy::await_holding_refcell_ref)]
pub async fn event(&self) -> Result<Option<DrmEvent>, DrmError> {
if self.events.is_empty() {