Linux/wlr capture delivers ~2/3 of the requested frame rate (pacing sleeps before requesting the frame)

オープン
#5,751 コメント 4 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
3/5
見積もり時間
1〜2日
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
cpp, linux

調査の方向性

Start in src/platform/linux/wlgrab.cpp at wlr_ram_t::capture and wlr_dmabuf_t::capture, then inspect snapshot() and the existing unpaced PipeWire capture path. Reproduce the reported 60 Hz case and trace when pacing, the screencopy request, and compositor response occur. Done means wlr capture approaches the requested rate when the source and encoder can sustain it, without regressing the idle-screen behavior referenced in #5748.

索引モデルが issue の本文から書いたものです。

説明

Is there an existing issue for this?
  • I have searched the existing issues
Describe the Bug

On the wlr capture path, the delivered frame rate is capped at roughly two thirds of the
requested rate, regardless of codec, resolution, encoder load or Sunshine version. With a
60 fps client request on a 60 Hz output I get a steady 41 fps; the same host sustains
59.9 fps when an independent wlr-screencopy consumer captures the same output with the
same VA-API encoder.

I believe the cause is the order of operations in the wlr capture loop
(src/platform/linux/wlgrab.cpp, wlr_ram_t::capture / wlr_dmabuf_t::capture):

while (true) {
  platf::handle_pacing(next_frame, delay, sleep_overshoot_logger);  // sleep a full frame interval
  auto status = snapshot(...);   // only now request a frame, then block until the compositor answers
  push_captured_image_cb(...);
}

snapshot() issues the screencopy request after the pacing sleep, so the compositor
cannot answer until its next frame. The delivered interval is therefore quantised to the
output's vblank and, since the request lands at an arbitrary phase, averages about
1.5 vblanks — 25 ms at 60 Hz, which is the 41 fps I measure.

The PipeWire path already has unpaced capture (#5629); wlr does not.

Evidence

Host: Ubuntu 24.04, AMD RX 7900 (VA-API), sway on its headless backend, virtual output
1920x1080. Capture source is glxgears fullscreen, verified window-by-window at 61.8–62.2 fps
for every measurement below. Client is Moonlight 12.2 on Android TV. Rates are read from
Moonlight's performance overlay.

The ceiling does not move for any of these:

varied values tried delivered
codec AV1 / H.264 41 / 41
Sunshine version 2026.516 / 2026.918 41 / 41
thread priority all 46 threads renice −15 41
resolution 1080p / 720p 41 / 41

Independent consumer on the same output, same host, same encoder:

capture encoder frames / duration fps
wf-recorder libx264 796 / 12.98 s 61.3
wf-recorder h264_vaapi 836 / 13.96 s 59.9
Sunshine vaapi — 41

The ceiling tracks the output's refresh, not the requested rate. Holding the client at
90 fps and forcing the output back to 60 Hz collapses it again, which is what points at the
vblank rather than at delay itself:

client request output delivered host processing avg
60 fps 60 Hz 41 15.5 ms
90 fps 60 Hz 42–44 15.1–16.8 ms
90 fps 90 Hz 54–56 12.3–12.8 ms
120 fps 120 Hz 64–73 10.9–12.4 ms

Host processing latency averages 15.5 ms throughout, so the encoder is not the limit — it
would allow ~64 fps on its own.

Expected Behavior

Delivered frame rate should approach the requested rate when the source and the encoder can
both sustain it, as the same protocol does for other consumers.

Additional Context

#5748 is touching snapshot() and the request timing in the same file for a different reason
(idle-screen compositor CPU); whoever works on that area may want this case in view.

Host Operating System

Linux

Operating System Version

Ubuntu 24.04.3 LTS, kernel 7.0.0-31-generic

Architecture

amd64

Sunshine commit or version

2026.918.174827 (also reproduced on 2026.516.143833)

GPU Type

AMD

GPU Model

Radeon RX 7900

GPU Driver/Mesa Version

amdgpu / Mesa (VA-API)

Capture Method

wlr (wlgrab)

主要言語
C++
スター
43k
フォーク
2.4k
平均マージ
1日 15時間
マージ済み PR(30日)
105

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

LizardByte/Sunshine のほかの issue

LizardByte/Sunshine の issue をすべて見る

似ている issue

C++ の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。