1
0
Fork 0
forked from wry/wry

metal: implement direct scanout

This commit is contained in:
Julian Orth 2024-02-18 20:29:23 +01:00
parent fed2ceb8b5
commit da84e9ec27
25 changed files with 682 additions and 148 deletions

View file

@ -1,24 +1,45 @@
use {
crate::{gfx_api::GfxContext, utils::oserror::OsError},
crate::{gfx_api::GfxContext, utils::oserror::OsError, video::Modifier},
ahash::AHashMap,
byteorder::{NativeEndian, WriteBytesExt},
std::{io::Write, rc::Rc},
thiserror::Error,
uapi::{c, OwnedFd},
};
pub struct DrmFeedback {
linear_ids!(DrmFeedbackIds, DrmFeedbackId);
#[derive(Debug)]
pub struct DrmFeedbackShared {
pub fd: Rc<OwnedFd>,
pub size: usize,
pub indices: Vec<u16>,
pub main_device: c::dev_t,
pub indices: AHashMap<(u32, Modifier), u16>,
}
#[derive(Debug)]
pub struct DrmFeedback {
pub id: DrmFeedbackId,
pub shared: Rc<DrmFeedbackShared>,
pub tranches: Vec<DrmFeedbackTranche>,
}
#[derive(Clone, Debug)]
pub struct DrmFeedbackTranche {
pub device: c::dev_t,
pub indices: Vec<u16>,
pub scanout: bool,
}
impl DrmFeedback {
pub fn new(ctx: &dyn GfxContext) -> Result<Self, DrmFeedbackError> {
let dev_t = uapi::fstat(ctx.gbm().drm.raw())
pub fn new(
ids: &DrmFeedbackIds,
render_ctx: &dyn GfxContext,
) -> Result<Self, DrmFeedbackError> {
let main_device = uapi::fstat(render_ctx.gbm().drm.raw())
.map_err(OsError::from)?
.st_rdev;
let data = create_fd_data(ctx);
let (data, index_map) = create_fd_data(render_ctx);
let mut memfd =
uapi::memfd_create("drm_feedback", c::MFD_CLOEXEC | c::MFD_ALLOW_SEALING).unwrap();
memfd.write_all(&data).unwrap();
@ -28,27 +49,69 @@ impl DrmFeedback {
c::F_SEAL_SEAL | c::F_SEAL_GROW | c::F_SEAL_SHRINK | c::F_SEAL_WRITE,
)
.unwrap();
let num_indices = data.len() / 16;
let indices = (0..num_indices).map(|v| v as u16).collect();
Ok(Self {
fd: Rc::new(memfd),
size: data.len(),
indices,
main_device: dev_t,
id: ids.next(),
tranches: vec![DrmFeedbackTranche {
device: main_device,
indices: (0..index_map.len()).map(|v| v as u16).collect(),
scanout: false,
}],
shared: Rc::new(DrmFeedbackShared {
fd: Rc::new(memfd),
size: data.len(),
main_device,
indices: index_map,
}),
})
}
pub fn for_scanout(
&self,
ids: &DrmFeedbackIds,
devnum: c::dev_t,
formats: &[(u32, Modifier)],
) -> Result<Option<Self>, DrmFeedbackError> {
let mut tranches = vec![];
{
let mut indices = vec![];
for (format, modifier) in formats {
if let Some(idx) = self.shared.indices.get(&(*format, *modifier)) {
indices.push(*idx);
}
}
if indices.len() > 0 {
tranches.push(DrmFeedbackTranche {
device: devnum,
indices,
scanout: true,
});
} else {
return Ok(None);
}
}
tranches.extend(self.tranches.iter().cloned());
Ok(Some(Self {
id: ids.next(),
shared: self.shared.clone(),
tranches,
}))
}
}
fn create_fd_data(ctx: &dyn GfxContext) -> Vec<u8> {
fn create_fd_data(ctx: &dyn GfxContext) -> (Vec<u8>, AHashMap<(u32, Modifier), u16>) {
let mut vec = vec![];
let mut map = AHashMap::new();
let mut pos = 0;
for (format, info) in &*ctx.formats() {
for modifier in &info.read_modifiers {
vec.write_u32::<NativeEndian>(*format).unwrap();
vec.write_u32::<NativeEndian>(0).unwrap();
vec.write_u64::<NativeEndian>(*modifier).unwrap();
map.insert((*format, *modifier), pos);
pos += 1;
}
}
vec
(vec, map)
}
#[derive(Debug, Error)]