diff options
| author | dangofactory <root@dangofactory.net> | 2026-10-11 12:37:31 +0900 |
|---|---|---|
| committer | dangofactory <root@dangofactory.net> | 2026-10-11 12:37:31 +0900 |
| commit | ea9addfa0c8389091da3162bc67fd464cc53751e (patch) | |
| tree | 1bf7152e10f4b2b4d5ca953e2090bfedc8ba1872 | |
| parent | e3a67e2c59d7251dca91f8d7fa55277963081562 (diff) | |
| download | 98fmplayer-main.tar.gz 98fmplayer-main.tar.bz2 98fmplayer-main.zip | |
Unthrottled async presenting (previous commit) lets the app's frame
writes race picom's composite read: users see a vertical tear inside
the FMDSP area about once every few seconds. Re-enabling client vsync
alone brings back the 47fps missed-vblank judder (33% of frame-clock
ticks at 16.7-33ms). Both fail together.
Fix: keep client vsync ON and throttle queue_draw to 30fps in the
frame-clock tick, so every presented frame lands uniformly at ~33.3ms:
measured 29.6 visible fps, intervals avg 33.8ms, CPU down (app 11%,
Xorg 11%, picom 3.5%), no stalls. FM_FPS=60 restores full-rate drawing,
FM_NO_VSYNC=1 restores the async experiment.
| -rw-r--r-- | gtk/main.c | 32 |
1 files changed, 23 insertions, 9 deletions
@@ -573,9 +573,24 @@ static gboolean tick_cb(GtkWidget *w, GdkFrameClock *frame_clock, gpointer p) { (void)w; - (void)frame_clock; (void)p; - gtk_widget_queue_draw(g.fmdsp_widget); + /* 描画レート上限(既定 30fps)。クライアント vsync を有効にしたまま 60fps で + queue_draw すると vblank を 1/3 の割合で乗り遅れて 16.7/33ms の混在(ジャダ)に、 + vsync を無効にすると picom の合成読み取りと競合して FMDSP 内に縦線(tearing)が入る。 + 実測 (2026-10-11): vsync有効+60要求=可視47fps不均一 / vsync無効=可視55fpsだが縦線。 + vsync有効+30要求なら毎フレーム均一 33.3ms で tearing もジャダも出ない。 + FM_FPS=60 で従来の全フレーム描画に戻せる。 */ + static gint64 last_draw_us = 0; + static gint64 min_interval_us = -1; + if (min_interval_us < 0) { + const char *fps = getenv("FM_FPS"); + min_interval_us = (fps && atoi(fps) > 0) ? (gint64)(1000000.0 / atoi(fps)) : 33333; + } + gint64 now = gdk_frame_clock_get_frame_time(frame_clock); + if (now - last_draw_us >= min_interval_us) { + last_draw_us = now; + gtk_widget_queue_draw(g.fmdsp_widget); + } if (getenv("FM_LOAD_STATS")) { static int n = 0; if ((n++ % 120) == 0) { @@ -838,13 +853,12 @@ int main(int argc, char **argv) { #endif fft_init_table(); fmplayer_font_rom_load(&g.font98); - /* GtkGLArea のスワップ(クライアント側 vsync)は picom の合成と二重になり、 - 実測で tick 間隔の 33% が 16.7-33ms(vblank 1枚落ち、可視 47fps)になる。 - クライアント側を外して picom 側の vsync だけに任せると可視 53fps、CPU 増なし、 - ストールなし(2026-10-11 実測、xrate 125Hz × 10s × 2構成)。 - よって既定はクライアント vsync 無効。戻したければ FM_VSYNC=1。 */ - if (getenv("FM_VSYNC")) setenv("vblank_mode", "1", 1); - else setenv("vblank_mode", "0", 1); + /* GtkGLArea のスワップ(クライアント側 vsync)を有効に戻す。無効化すると + picom の合成読み取りとフレーム書き込みが競合し、FMDSP 内に縦線が入る + (2026-10-11 実測でユーザーが確認)。ジャダ対策は tick_cb の 30fps 上限で行う。 + 実験で無効にしたいときは FM_NO_VSYNC=1。 */ + if (getenv("FM_NO_VSYNC")) setenv("vblank_mode", "0", 1); + else setenv("vblank_mode", "1", 1); gtk_init(&argc, &argv); { GList *iconlist = 0; |
