https://gitlab.synchro.net/main/sbbs/-/commit/cf716c8c543841719d32b3fe
Modified Files:
src/doors/syncscumm/door/sst_io.c src/doors/syncscumm/test/test_sst_io_bottom_dirty.c
Log Message:
syncscumm: check sixel bottom-strand before emitting any dirty box
sst_dirty_sixel_present()'s bottom-strand `return 0` (full-frame
fallback, added in the previous commit) lived inside the box-emit
loop, and boxes are written to the wire as each one succeeds in
raster order. A frame that dirties an earlier box AND a later
bottom-strand box -- the real stale-cursor case always does: an
erase box above the cursor's old spot plus the bottom box itself --
already had the earlier box's bytes on the wire by the time the
bottom box hit `return 0`. The caller then saw a 0 return, believed
nothing was sent, and ALSO emitted a full frame, so the wire carried
a partial dirty box plus a full frame on exactly the frames this fix
targets. That violates the clean-abandon invariant the parallel JXL
present function documents: never stack a full frame on top of
already-sent partial rects. Visually harmless (the full frame
overwrites) but wasteful on the hot path.
Make the fallback atomic: run a pre-pass over every coalesced box,
computing its display rect + clamped height exactly as the emit loop
does, and return 0 immediately -- before a single out_put() -- if any
emittable box (rw > 0) strands. A box with rw <= 0 is the existing
empty-width `continue` case and must not itself count as stranding.
To avoid duplicating the ~25 lines of NN-mapping/cell-snap/vstep math
in two loops, factor it into a new static helper,
sst_box_display_rect(), called from both the pre-pass and the emit
loop; the emit loop no longer needs its own inner strand check, since
the pre-pass already guarantees no box in the frame strands.
Tighten test_sst_io_bottom_dirty.c to match: it used to scan for the
largest sixel raster Pv and tolerate an earlier, smaller raster
header ahead of the full frame. With the atomic fix a bottom-strand
present() must put exactly ONE raster header on the wire (the full
frame), so the test now counts headers and asserts cnt == 1 for both
the bottom-strand case and the ordinary dirty-rect case. Confirmed
this tightened assertion goes RED (cnt == 1 fails, two headers seen)
when compiled against the previous commit's pre-pass-less sst_io.c,
and GREEN after this fix.
---
þ Synchronet þ Vertrauen þ Home of Synchronet þ [vert/cvs/bbs].synchro.net