refactor: split cargo workspace
This commit is contained in:
parent
5db14936e7
commit
1c21bd1259
695 changed files with 32023 additions and 44964 deletions
|
|
@ -1,215 +1,35 @@
|
|||
pub use jay_output_schedule::*;
|
||||
|
||||
use {
|
||||
crate::{
|
||||
async_engine::AsyncEngine,
|
||||
backend::HardwareCursor,
|
||||
ifs::wl_output::PersistentOutputState,
|
||||
io_uring::{IoUring, IoUringError},
|
||||
state::{ConnectorData, State},
|
||||
utils::{
|
||||
asyncevent::AsyncEvent, cell_ext::CellExt, clonecell::CloneCell, errorfmt::ErrorFmt,
|
||||
numcell::NumCell,
|
||||
},
|
||||
},
|
||||
futures_util::{FutureExt, select},
|
||||
num_traits::ToPrimitive,
|
||||
std::{cell::Cell, rc::Rc},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
enum Change {
|
||||
/// The backend has applied the latest changes.
|
||||
None,
|
||||
/// There are changes that the backend is not yet aware of.
|
||||
Scheduled,
|
||||
/// The backend is aware that there are changes and will apply them as part of the
|
||||
/// next latch event.
|
||||
AwaitingLatch,
|
||||
}
|
||||
|
||||
pub struct OutputSchedule {
|
||||
changed: AsyncEvent,
|
||||
run: Cell<bool>,
|
||||
|
||||
connector: Rc<ConnectorData>,
|
||||
hardware_cursor: CloneCell<Option<Rc<dyn HardwareCursor>>>,
|
||||
|
||||
persistent: Rc<PersistentOutputState>,
|
||||
|
||||
last_present_nsec: Cell<u64>,
|
||||
cursor_delta_nsec: Cell<Option<u64>>,
|
||||
|
||||
ring: Rc<IoUring>,
|
||||
eng: Rc<AsyncEngine>,
|
||||
|
||||
vrr_enabled: Cell<bool>,
|
||||
|
||||
hardware_cursor_change: Cell<Change>,
|
||||
software_cursor_change: Cell<Change>,
|
||||
|
||||
iteration: NumCell<u64>,
|
||||
}
|
||||
|
||||
impl OutputSchedule {
|
||||
pub fn new(
|
||||
state: &State,
|
||||
connector: &Rc<ConnectorData>,
|
||||
persistent: &Rc<PersistentOutputState>,
|
||||
) -> Self {
|
||||
let slf = Self {
|
||||
changed: Default::default(),
|
||||
run: Default::default(),
|
||||
connector: connector.clone(),
|
||||
ring: state.ring.clone(),
|
||||
eng: state.eng.clone(),
|
||||
vrr_enabled: Default::default(),
|
||||
hardware_cursor_change: Cell::new(Change::None),
|
||||
software_cursor_change: Cell::new(Change::None),
|
||||
hardware_cursor: Default::default(),
|
||||
persistent: persistent.clone(),
|
||||
last_present_nsec: Default::default(),
|
||||
cursor_delta_nsec: Default::default(),
|
||||
iteration: Default::default(),
|
||||
};
|
||||
if let Some(hz) = persistent.vrr_cursor_hz.get() {
|
||||
slf.set_cursor_hz(state, hz);
|
||||
}
|
||||
slf
|
||||
impl OutputSchedulePersistent for PersistentOutputState {
|
||||
fn vrr_cursor_hz(&self) -> Option<f64> {
|
||||
self.vrr_cursor_hz.get()
|
||||
}
|
||||
|
||||
pub async fn drive(self: Rc<Self>) {
|
||||
loop {
|
||||
self.run_once().await;
|
||||
while !self.run.take() {
|
||||
self.changed.triggered().await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trigger(&self) {
|
||||
let trigger = self.vrr_enabled.get()
|
||||
&& self.cursor_delta_nsec.is_some()
|
||||
&& (self.software_cursor_change.get() == Change::Scheduled
|
||||
|| self.hardware_cursor_change.get() == Change::Scheduled);
|
||||
if trigger {
|
||||
self.run.set(true);
|
||||
self.changed.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn latched(&self) {
|
||||
self.last_present_nsec.set(self.eng.now().nsec());
|
||||
if self.software_cursor_change.get() == Change::AwaitingLatch {
|
||||
self.software_cursor_change.set(Change::None);
|
||||
}
|
||||
if self.hardware_cursor_change.get() == Change::AwaitingLatch {
|
||||
self.hardware_cursor_change.set(Change::None);
|
||||
}
|
||||
self.iteration.fetch_add(1);
|
||||
self.trigger();
|
||||
}
|
||||
|
||||
pub fn vrr_enabled(&self) -> bool {
|
||||
self.vrr_enabled.get()
|
||||
}
|
||||
|
||||
pub fn set_vrr_enabled(&self, enabled: bool) {
|
||||
self.vrr_enabled.set(enabled);
|
||||
self.trigger();
|
||||
}
|
||||
|
||||
pub fn set_cursor_hz(&self, _state: &State, hz: f64) {
|
||||
let (hz, delta) = match map_cursor_hz(hz) {
|
||||
None => {
|
||||
log::warn!("Ignoring cursor frequency {hz}");
|
||||
return;
|
||||
}
|
||||
Some(v) => v,
|
||||
};
|
||||
self.persistent.vrr_cursor_hz.set(hz);
|
||||
self.connector.head_managers.handle_cursor_hz_change(hz);
|
||||
self.cursor_delta_nsec.set(delta);
|
||||
self.trigger();
|
||||
}
|
||||
|
||||
pub fn set_hardware_cursor(&self, hc: &Option<Rc<dyn HardwareCursor>>) {
|
||||
self.hardware_cursor.set(hc.clone());
|
||||
}
|
||||
|
||||
pub fn defer_cursor_updates(&self) -> bool {
|
||||
self.vrr_enabled.get() && self.cursor_delta_nsec.is_some()
|
||||
}
|
||||
|
||||
pub fn hardware_cursor_changed(&self) {
|
||||
if self.hardware_cursor_change.get() == Change::None {
|
||||
self.hardware_cursor_change.set(Change::Scheduled);
|
||||
self.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn software_cursor_changed(&self) {
|
||||
if self.software_cursor_change.get() == Change::None {
|
||||
self.software_cursor_change.set(Change::Scheduled);
|
||||
self.trigger();
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_once(&self) {
|
||||
loop {
|
||||
if self.hardware_cursor_change.get() != Change::Scheduled
|
||||
&& self.software_cursor_change.get() != Change::Scheduled
|
||||
{
|
||||
return;
|
||||
}
|
||||
if !self.vrr_enabled.get() {
|
||||
return;
|
||||
}
|
||||
let Some(duration) = self.cursor_delta_nsec.get() else {
|
||||
return;
|
||||
};
|
||||
let iteration = self.iteration.get();
|
||||
let next_present = self.last_present_nsec.get().saturating_add(duration);
|
||||
let res: Result<(), IoUringError> = select! {
|
||||
_ = self.changed.triggered().fuse() => continue,
|
||||
v = self.ring.timeout(next_present).fuse() => v,
|
||||
};
|
||||
if let Err(e) = res {
|
||||
log::error!("Could not wait for timer to expire: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
if iteration == self.iteration.get() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.commit_cursor();
|
||||
}
|
||||
|
||||
pub fn commit_cursor(&self) {
|
||||
if self.hardware_cursor_change.get() == Change::Scheduled {
|
||||
if let Some(hc) = self.hardware_cursor.get() {
|
||||
hc.damage();
|
||||
}
|
||||
self.hardware_cursor_change.set(Change::AwaitingLatch);
|
||||
}
|
||||
if self.software_cursor_change.get() == Change::Scheduled {
|
||||
self.connector.damage();
|
||||
self.software_cursor_change.set(Change::AwaitingLatch);
|
||||
}
|
||||
fn set_vrr_cursor_hz(&self, hz: Option<f64>) {
|
||||
self.vrr_cursor_hz.set(hz);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_cursor_hz(hz: f64) -> Option<(Option<f64>, Option<u64>)> {
|
||||
if hz <= 0.0 {
|
||||
return Some((Some(0.0), Some(u64::MAX)));
|
||||
}
|
||||
let delta = (1_000_000_000.0 / hz).to_u64();
|
||||
if delta.is_none() {
|
||||
if hz > 0.0 {
|
||||
return Some((None, None));
|
||||
}
|
||||
return None;
|
||||
}
|
||||
if delta == Some(0) {
|
||||
return Some((None, None));
|
||||
}
|
||||
Some((Some(hz), delta))
|
||||
pub fn create_output_schedule(
|
||||
state: &State,
|
||||
connector: &Rc<ConnectorData>,
|
||||
persistent: &Rc<PersistentOutputState>,
|
||||
) -> OutputSchedule {
|
||||
let damage_connector = connector.clone();
|
||||
let cursor_hz_connector = connector.clone();
|
||||
OutputSchedule::new(
|
||||
state.ring.clone(),
|
||||
state.eng.clone(),
|
||||
persistent.clone(),
|
||||
Rc::new(move || damage_connector.damage()),
|
||||
Rc::new(move |hz| cursor_hz_connector.head_managers.handle_cursor_hz_change(hz)),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue