use crate::frame::{object::Object, vulkan::Vulkan};
use crate::predictor::Controller;
use std::{cell::RefCell, rc::Rc, thread, time::Duration};
use wayland_client::{
protocol::{wl_output::WlOutput, wl_registry::WlRegistry},
Display, EventQueue, GlobalManager, Main,
};
use wayland_protocols::wlr::unstable::export_dmabuf::v1::client::{
zwlr_export_dmabuf_frame_v1::{CancelReason, Event},
zwlr_export_dmabuf_manager_v1::ZwlrExportDmabufManagerV1,
};
use wayland_protocols::unstable::xdg_output::v1::client::zxdg_output_manager_v1::ZxdgOutputManagerV1;
use wayland_protocols::unstable::xdg_output::v1::client::zxdg_output_v1::Event::Description;
const DELAY_SUCCESS: Duration = Duration::from_millis(100);
const DELAY_FAILURE: Duration = Duration::from_millis(1000);
#[derive(Clone)]
pub struct Capturer {
event_queue: Rc<RefCell<EventQueue>>,
globals: GlobalManager,
dmabuf_manager: Main<ZwlrExportDmabufManagerV1>,
vulkan: Rc<Vulkan>,
registry: Main<WlRegistry>,
xdg_output_manager: Main<ZxdgOutputManagerV1>,
}
impl super::Capturer for Capturer {
fn run(&self, output_name: &str, controller: Controller) {
let controller = Rc::new(RefCell::new(controller));
self.globals
.list()
.iter()
.filter(|(_, interface, _)| interface == "wl_output")
.for_each(|(id, _, _)| {
let output = Rc::new(self.registry.bind::<WlOutput>(1, *id));
let capturer = Rc::new(self.clone());
let controller = controller.clone();
let desired_output = output_name.to_string();
self.xdg_output_manager
.get_xdg_output(&output)
.quick_assign(move |_, event, _| match event {
Description { description } if description.contains(&desired_output) => {
log::debug!(
"Using output '{}' for config '{}'",
description,
desired_output,
);
capturer
.clone()
.capture_frame(controller.clone(), output.clone());
}
_ => {}
});
});
loop {
self.event_queue
.borrow_mut()
.dispatch(&mut (), |_, _, _| {})
.expect("Error running wlroots capturer main loop");
}
}
}
impl Default for Capturer {
fn default() -> Self {
let display = Display::connect_to_env().unwrap();
let mut event_queue = display.create_event_queue();
let attached_display = display.attach(event_queue.token());
let registry = attached_display.get_registry();
let globals = GlobalManager::new(&attached_display);
event_queue.sync_roundtrip(&mut (), |_, _, _| {}).unwrap();
let dmabuf_manager = globals
.instantiate_exact::<ZwlrExportDmabufManagerV1>(1)
.expect("Unable to init export_dmabuf_manager");
let xdg_output_manager = globals
.instantiate_exact::<ZxdgOutputManagerV1>(3)
.expect("Unable to init xdg_output_manager");
let vulkan = Rc::new(Vulkan::new().expect("Unable to initialize Vulkan"));
Self {
event_queue: Rc::new(RefCell::new(event_queue)),
globals,
registry,
dmabuf_manager,
vulkan,
xdg_output_manager,
}
}
}
impl Capturer {
fn capture_frame(
self: Rc<Self>,
controller: Rc<RefCell<Controller>>,
output: Rc<Main<WlOutput>>,
) {
let mut frame = Object::default();
self.dmabuf_manager
.capture_output(0, &output)
.quick_assign(move |data, event, _| match event {
Event::Frame {
width,
height,
num_objects,
..
} => {
frame.set_metadata(width, height, num_objects);
}
Event::Object {
index, fd, size, ..
} => {
frame.set_object(index, fd, size);
}
Event::Ready { .. } => {
let luma = self
.vulkan
.luma_percent(&frame)
.expect("Unable to compute luma percent");
controller.borrow_mut().adjust(luma);
data.destroy();
thread::sleep(DELAY_SUCCESS);
self.clone().capture_frame(controller.clone(), output.clone());
}
Event::Cancel { reason } => {
data.destroy();
if reason == CancelReason::Permanent {
panic!("Frame was cancelled due to a permanent error. If you just disconnected screen, this is not implemented yet.");
} else {
log::error!("Frame was cancelled due to a temporary error, will try again.");
thread::sleep(DELAY_FAILURE);
self.clone().capture_frame(controller.clone(), output.clone());
}
}
_ => unreachable!(),
});
}
}