use std::ops::Range;
use crate::registry::{PlaneRegistry, PlaneType};
#[must_use]
pub fn stacks_by_plane_id(registry: &PlaneRegistry, crtc_index: u32) -> bool {
let mut planes = registry.for_crtc(crtc_index).peekable();
planes.peek().is_some()
&& planes.all(|plane| plane.plane_type == PlaneType::Cursor || plane.zpos_min.is_none())
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct Choice {
pub run: Range<usize>,
pub canvas: Option<usize>,
}
#[derive(Debug)]
pub(crate) struct PlaneOrder {
pre: Vec<Option<usize>>,
pre_plane: Vec<Option<usize>>,
suf: Vec<Option<usize>>,
suf_plane: Vec<Option<usize>>,
}
impl PlaneOrder {
pub(crate) fn new(n: usize, m: usize, mut fits: impl FnMut(usize, usize) -> bool) -> Self {
let mut pre = vec![None; n + 1];
let mut pre_plane = vec![None; n];
pre[0] = Some(0);
for i in 0..n {
let Some(from) = pre[i] else { break };
if let Some(j) = (from..m).find(|&j| fits(i, j)) {
pre_plane[i] = Some(j);
pre[i + 1] = Some(j + 1);
}
}
let mut suf = vec![None; n + 1];
let mut suf_plane = vec![None; n];
suf[n] = Some(m);
for i in (0..n).rev() {
let Some(below) = suf[i + 1] else { break };
if let Some(j) = (0..below).rev().find(|&j| fits(i, j)) {
suf_plane[i] = Some(j);
suf[i] = Some(j);
}
}
Self {
pre,
pre_plane,
suf,
suf_plane,
}
}
pub(crate) fn choose(
&self,
max_placed: usize,
forced: Option<&Range<usize>>,
hosts_canvas: Option<&dyn Fn(usize) -> bool>,
cost: impl Fn(usize) -> i64,
) -> Option<Choice> {
let n = self.pre_plane.len();
let mut best: Option<(Choice, usize, i64)> = None;
for a in 0..=n {
let Some(low) = self.pre[a] else { break };
for b in a..=n {
let Some(high) = self.suf[b] else { continue };
if forced.is_some_and(|forced| a > forced.start || b < forced.end) {
continue;
}
let placed = n - (b - a);
if placed > max_placed {
continue;
}
let canvas = match hosts_canvas {
Some(hosts) if a < b => {
let Some(j) = (low..high).rev().find(|&j| hosts(j)) else {
continue;
};
Some(j)
}
_ if low > high => continue,
_ => None,
};
let total: i64 = (a..b).map(&cost).sum();
if best
.as_ref()
.is_none_or(|(_, p, c)| placed > *p || (placed == *p && total < *c))
{
best = Some((Choice { run: a..b, canvas }, placed, total));
}
}
}
best.map(|(choice, _, _)| choice)
}
pub(crate) fn plane_of(&self, i: usize, choice: &Choice) -> Option<usize> {
if i < choice.run.start {
self.pre_plane[i]
} else if i >= choice.run.end {
self.suf_plane[i]
} else {
None
}
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct Position {
pub zpos: u64,
pub plane: Option<u32>,
pub on_canvas: bool,
}
pub(crate) fn plane_order_consistent(positions: &[Position]) -> bool {
positions.iter().all(|x| {
positions.iter().filter(|y| x.zpos < y.zpos).all(|y| {
match (x.plane, y.plane) {
(Some(px), Some(py)) => px < py || (px == py && x.on_canvas && y.on_canvas),
_ => false,
}
})
})
}