perf(portal): achieve 58-60fps PipeWire screen capture

- Force PipeWire quantum=512 via NODE_FORCE_QUANTUM (48000/512=93Hz scheduling)
- Switch to libx264 ultrafast/zerolatency with 6 threads
- Use two-phase poll_and_encode: blocking recv_timeout for first frame,
  non-blocking try_recv drain for subsequent frames
- Remove fps_limit from portal path (PW already rate-limits via quantum/KWin;
  fps_limit's min_interval was silently dropping ~10% of valid frames)
- Remove diagnostic instrumentation (TIMING/PIPEWIRE logs, timing fields,
  pw_stats counters)
- Add lightweight production stats: per-10s fps log + shutdown summary
- Prefer libx264 over libopenh264 (better quality at same speed)
This commit is contained in:
dailz
2026-05-30 08:44:15 +08:00
parent a83d146ed3
commit 74f4dc826d
6 changed files with 88 additions and 187 deletions

View File

@@ -304,15 +304,14 @@ fn run_portal_pipewire(args: Args) -> Result<()> {
poll.registry()
.register(&mut signals, mio::Token(1), mio::Interest::READABLE)?;
// 主事件循环(超时 10ms比 wlr-screencopy 更短,因为不依赖 Wayland fd 唤醒
// 10ms 超时的作用是让循环高频转动,以便及时处理 PipeWire 投递的帧
// 如果没有信号poll 最多阻塞 10ms 就会超时返回
// 主事件循环(非阻塞信号检测 + recv_timeout 等待帧
// poll 超时为 0ms非阻塞实际等待由 poll_and_encode 的 recv_timeout 实现
let mut running = true;
while running {
// poll 在此循环中只监听信号 fd,所以
// poll 在此循环中只监听信号 fd(非阻塞)
// - 收到 SIGINT/SIGTERM → 事件触发,设置 running=false
// - 超时 10ms → 事件为空,继续执行 poll_and_encode
poll.poll(&mut events, Some(std::time::Duration::from_millis(10)))
// - 无事件 → 立即返回,继续执行 poll_and_encode(内部 recv_timeout 等待帧)
poll.poll(&mut events, Some(std::time::Duration::from_millis(0)))
.unwrap_or_else(|e| {
if e.kind() == std::io::ErrorKind::Interrupted {
return;
@@ -321,7 +320,6 @@ fn run_portal_pipewire(args: Args) -> Result<()> {
running = false;
});
// 遍历事件,检查是否收到退出信号
for event in &events {
if event.token() == mio::Token(1) {
tracing::info!("Received quit signal");
@@ -334,7 +332,9 @@ fn run_portal_pipewire(args: Args) -> Result<()> {
// poll_and_encode 会从 PipeWire 缓冲区取出帧,
// 编码为 H.264 并推送。返回 true 表示还有更多帧待处理,
// 返回 false 表示当前没有帧了while 循环退出等待下一轮 poll
while state.poll_and_encode()? {}
if state.poll_and_encode(true)? {
while state.poll_and_encode(false)? {}
}
// Portal 状态机遇到致命错误时退出
if state.is_errored() {