summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordangofactory <root@dangofactory.net>2026-10-11 12:37:31 +0900
committerdangofactory <root@dangofactory.net>2026-10-11 12:37:31 +0900
commitea9addfa0c8389091da3162bc67fd464cc53751e (patch)
tree1bf7152e10f4b2b4d5ca953e2090bfedc8ba1872
parente3a67e2c59d7251dca91f8d7fa55277963081562 (diff)
download98fmplayer-main.tar.gz
98fmplayer-main.tar.bz2
98fmplayer-main.zip
gtk: cap FMDSP redraw at 30fps and re-enable client vsyncHEADmastermain
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.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/gtk/main.c b/gtk/main.c
index 8708482..3220856 100644
--- a/gtk/main.c
+++ b/gtk/main.c
@@ -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;