use super::fd;
use super::protocol::linux_dmabuf::{zwp_linux_dmabuf_feedback_v1, zwp_linux_dmabuf_v1};
use super::{ObjectKind, RawEvent, WaylandShell};
pub(super) const DMABUF_VERSION: u32 = 4;
pub(super) fn decode_device(bytes: &[u8]) -> Option<u64> {
let bytes: [u8; 8] = bytes.try_into().ok()?;
Some(u64::from_ne_bytes(bytes))
}
pub(super) fn decode_event(
proxy: usize,
event: zwp_linux_dmabuf_feedback_v1::Event<'_>,
) -> Option<RawEvent> {
match event {
zwp_linux_dmabuf_feedback_v1::Event::MainDevice { device } => {
Some(RawEvent::DmabufMainDevice {
feedback: proxy,
device: decode_device(device),
})
}
zwp_linux_dmabuf_feedback_v1::Event::Done => Some(RawEvent::DmabufDone { feedback: proxy }),
zwp_linux_dmabuf_feedback_v1::Event::FormatTable { fd, .. } => {
fd::close(fd);
None
}
_ => None,
}
}
impl WaylandShell {
pub(super) fn add_dmabuf_feedback(&mut self) {
let manager = self.conn.dmabuf;
if manager.is_null() || !self.dmabuf_feedback.is_null() {
return;
}
let feedback = unsafe { zwp_linux_dmabuf_v1::get_default_feedback(manager) };
if feedback.is_null() {
return;
}
self.conn.watch(feedback, ObjectKind::DmabufFeedback);
self.dmabuf_feedback = feedback;
}
pub(super) fn dmabuf_main_device(&mut self, feedback: usize, device: Option<u64>) {
if feedback == self.dmabuf_feedback as usize {
self.pending_main_device = device;
}
}
pub(super) fn dmabuf_done(&mut self, feedback: usize) {
if feedback != self.dmabuf_feedback as usize {
return;
}
if self.main_device != self.pending_main_device {
crcbl_core::log::debug!(
"crcbl-shell: the compositor composites on DRM device {:?}",
self.pending_main_device
);
}
self.main_device = self.pending_main_device;
}
pub(super) fn remove_dmabuf_feedback(&mut self) {
let feedback = core::mem::replace(&mut self.dmabuf_feedback, core::ptr::null_mut());
unsafe {
self.conn
.release(feedback, zwp_linux_dmabuf_feedback_v1::destroy);
}
self.main_device = None;
self.pending_main_device = None;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_main_device_is_exactly_one_native_dev_t() {
let render = 0xe280_u64;
assert_eq!(decode_device(&render.to_ne_bytes()), Some(render));
assert_eq!(decode_device(&[]), None, "an empty array names nothing");
assert_eq!(
decode_device(&[0; 4]),
None,
"a 32-bit dev_t is not Linux's"
);
assert_eq!(decode_device(&[0; 16]), None, "two devices are not one");
}
}