• src/doors/termgfx/stats.c

    From Rob Swindell (on Windows@VERT to Git commit to main/sbbs/m on Thursday, July 23, 2026 00:08:00
    https://gitlab.synchro.net/main/sbbs/-/commit/9f0bfde96ee70ab98c147c33
    Added Files:
    src/doors/termgfx/stats.c stats.h src/doors/termgfx/test/test_stats.c Modified Files:
    src/doors/syncdoom/syncdoom.c src/doors/syncduke/syncduke_io.c src/doors/termgfx/CMakeLists.txt src/doors/termgfx/test/CMakeLists.txt
    Log Message:
    termgfx: share the Ctrl-S stats row's window and fields

    SyncDOOM, SyncDuke and SyncRetro each grew their own copy of the same
    status strip: a rolling ~2s window over emitted frames and wire bytes, and
    a readout starting

    " <tier> <fps>fps <rate> lag <cur>/<min>ms depth <n>[/auto]"

    before each door appends its own fields. Three copies, three chances to
    drift, and they had drifted: SyncRetro printed raw KB/s, so a fast link
    read "1382KB/s" where its siblings read "1.3MB/s", and it clamped none of
    its numbers, so an outlier sample could widen the strip past the row and
    wrap it onto the game view.

    termgfx/stats.[ch] holds the part that has to read the same everywhere --
    the window arithmetic (termgfx_stats_frame/_roll), the throughput token
    that abbreviates past 999KB/s, the shared head, and the " evdev/nat" and
    " x2" tokens SyncDOOM and SyncDuke had a copy of each. What stays in the
    doors is painting: they disagree about which row is free, how output
    reaches the wire, and what else competes for the row -- SyncRetro shares
    it with a volume toast.

    The strips are byte-identical to before except SyncRetro's, which gains
    the abbreviation and the clamps. SyncDuke's stderr log line keeps raw
    KB/s deliberately: a log is grepped and plotted, where a unit that changes
    with the value is a nuisance; only the strip, where width costs a column, abbreviates.

    SyncRetro's own half of this landed in the working tree ahead of this
    commit, with the idle-timeout change earlier in the batch -- so this adds
    the module it already calls, and converts the other two.

    test_stats covers the KB/s-to-MB/s threshold either side of 999, the
    clamps, the window (including across a millisecond-clock wrap) and both
    tokens. Only MSVC was compiled here; uncrustify was not available on that machine, so the new code was written to the house style by hand.

    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net
  • From Rob Swindell (on Debian L@VERT to Git commit to main/sbbs/m on Saturday, July 25, 2026 23:10:00
    https://gitlab.synchro.net/main/sbbs/-/commit/ced6dbbaecd42f31c0ac5000
    Modified Files:
    src/doors/termgfx/stats.c termgfx_termio.c
    Log Message:
    termgfx: true aspect on the fitted image, and don't call 1fps "no data"

    Two things a live F4 sixel session on SyncTERM turned up, neither of them
    new.

    THE SHAPE. termgfx_geom_fit()'s 8% allowance stretches away a thin
    leftover bar so a near-fit fills the canvas, which is right where the bar
    is an accident of the canvas. It is wrong here, because the sixel tier manufactures its own: it reserves the bottom text row for the stats and
    idle strips, so a canvas that fitted exactly becomes height-limited and
    leaves a side bar, which the allowance then hides by stretching the
    picture back out. At 80x25 that is a 4% vertical squash -- 640x384 where
    the source wants 614x384 -- while the JXL tier reserves nothing, fits
    640x400 exactly, and stays true. Two tiers disagreeing about the shape of
    the same game is the tell, and only that geometry shows it: on a canvas
    where the fit is width-limited there is no bar and nothing stretches,
    which is why it survived the measurements taken there.

    Fit at true aspect instead (max_stretch_pct 0), which is what
    syncconquer's own fit already passes. Letterboxing 13px a side is the
    cheaper mistake than reshaping the game.

    THE READOUT. fps was frames * 1000 / elapsed, truncated. A window is ~1s,
    so a scene drawing ONE frame in it came out as zero -- and the strip
    renders zero as "-fps -KB/f", which means "nothing drawn yet". A slow but perfectly healthy scene (an adventure sitting in a static room with one
    banner animating) reported itself as dead. Round instead of truncate, and
    keep a flag for "a window has closed with frames in it" so "-" can only
    ever mean startup. Bytes per frame now comes straight from the window
    rather than from dividing two rounded numbers, which lost accuracy exactly where the numbers are small. The same truncation was in stats.c's shared window, so the sibling doors under-reported slow scenes too; fixed there
    as well.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

    ---
    þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net