diff options
| -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; |
