This commit is contained in:
2026-09-09 23:40:21 +02:00
parent 3ad0b59d8c
commit 66c2d49ffb
6 changed files with 23 additions and 404 deletions
+6 -36
View File
@@ -7,12 +7,14 @@
//!
//! The pixels are never mapped into this process. A capture buffer goes straight
//! to a subsurface for display, so the compositor writes those pages and samples
//! them again itself.
//! them again itself. Live previews are always on.
use std::error::Error;
use std::os::fd::AsFd;
use std::time::{Duration, Instant};
use crate::Target;
use wayland_client::protocol::{
wl_buffer::{self, WlBuffer},
wl_callback, wl_output, wl_shm,
@@ -30,29 +32,7 @@ use wayland_protocols::wp::viewporter::client::wp_viewport::WpViewport;
use crate::app::App;
use crate::shm;
use crate::target::{Kind, Target};
/// Which tiles keep updating after the first frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Live {
/// Every tile.
All,
/// Only the selected tile: much cheaper, and still reads as alive.
Current,
/// Nothing: one snapshot each, a picker rather than an expose.
None,
}
impl Live {
pub fn parse(s: &str) -> Result<Self, String> {
match s.trim() {
"all" => Ok(Live::All),
"current" => Ok(Live::Current),
"none" => Ok(Live::None),
other => Err(format!("{other:?} is not all, current or none")),
}
}
}
use crate::target::Kind;
/// One capture buffer. `busy` means the compositor still holds it — either it is
/// on screen or a capture is writing into it — so we must not scribble over it.
@@ -202,9 +182,8 @@ impl App {
tile.settled = true;
continue;
}
// Only a tile that will be re-captured needs a second buffer, and a
// display's is the size of the whole screen.
let slots = if self.live == Live::None || tile.target.kind == Kind::Output {
// Always 2 buffers for live preview; display gets full-screen buffer.
let slots = if tile.target.kind == Kind::Output {
1
} else {
2
@@ -301,9 +280,6 @@ impl App {
/// Ask for the next frame callback. A commit is needed for the compositor to
/// schedule one, and an empty commit is enough.
pub fn arm_frame_callback(&mut self, qh: &QueueHandle<Self>) {
if self.live == Live::None {
return;
}
if let Some(surface) = self.surface.clone() {
surface.frame(qh, ());
surface.commit();
@@ -314,15 +290,9 @@ impl App {
/// the overlay is not being presented.
pub fn tick(&mut self, qh: &QueueHandle<Self>) {
self.stats.ticks += 1;
if self.live == Live::None {
return;
}
let interval = Duration::from_secs_f64(1.0 / self.fps.max(1) as f64);
let now = Instant::now();
for i in 0..self.tiles.len() {
if self.live == Live::Current && i != self.sel {
continue;
}
// A display tile shows this overlay, which shows the display tile:
// refreshing it never settles and costs a whole screen per frame.
if self.tiles[i].target.kind == Kind::Output {