• src/doors/syncretro/syncretro_quant.c syncretro_quant.h test_quant.c

    From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sat Jul 25 23:10:02 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/4ba867d0bad38dfe141b8f7e
    Modified Files:
    src/doors/syncretro/syncretro_quant.c syncretro_quant.h test_quant.c Log Message:
    syncretro: take the oldest sixel register, don't rebuild the map

    The colour->register map only ever grew, and a frame whose new colours
    could not fit threw the whole map away and rebuilt it from that frame.
    With shared colour registers -- which is what SyncTERM has, and what
    `CSI ? 1070 l` asks every other terminal for -- redefining a register
    recolours every pixel already on screen that was drawn with it, so a
    rebuild repaints the entire displayed frame in the wrong colours until
    the new pixel data lands on top of it.

    A console with a small fixed palette never reaches that: Intellivision
    has 16 colours, the NES 64. A console whose games fade or cycle their
    palette reaches it in seconds. Street Fighter II's attract mode re-tints
    every colour of a ~150-colour screen every frame, so the map saturated
    and then rebuilt on nearly every frame -- measured over its attract loop,
    150 of 256 registers changing meaning in a single frame, and 4.3 per
    frame on average.

    Give each register the generation that last drew with it and hand a new
    colour the least recently used one instead. The frame the terminal is displaying is the youngest generation, so its registers go last, and the colours a frame carries over are stamped before anything is taken -- a
    colour still on screen can never lose its register to a colour of the
    same frame.

    Over the same attract loop that leaves a worst frame of 37 registers
    rather than 150, and 0.5 per frame rather than 4.3. Every eviction of a displayed register was checked for a better candidate and none had one:
    where it still recolours, prev and current frame genuinely need more than
    256 colours between them. Games that never fill the map (tmnt, joust,
    pacman, xevious) are byte-for-byte unaffected.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)
  • From Rob Swindell (on Debian Linux)@1:103/705 to Git commit to main/sbbs/master on Sat Jul 25 23:10:02 2026
    https://gitlab.synchro.net/main/sbbs/-/commit/2afea7b8e82ff40b303757a5
    Modified Files:
    src/doors/syncretro/syncretro_quant.c syncretro_quant.h test_quant.c Log Message:
    syncretro: draw with a neighbour rather than recolour the screen

    Taking the least recently used sixel register is the best a frame can do
    while it insists on being reproduced exactly, and on a palette-cycling
    console that still is not good enough. A full-screen fade needs the
    colours of the frame the terminal is displaying AND the colours of the
    frame replacing it -- Street Fighter II's transitions want a little over
    300 between them, for 256 registers -- so some register on screen has to
    be redefined, and every pixel drawn with it turns the wrong colour until
    the repaint reaches it.

    That repaint is not quick. A transition frame is ~75KB of sixel at 80x25,
    and the bottom third of the picture sits ~40KB into it, so the lower part
    of the screen is the last to be made right and flashes visibly. (Emitting
    only the changed registers would not help: the palette is 3.6KB of those
    75KB.)

    So stop insisting. A colour that cannot have a register without
    recolouring the screen is drawn with the nearest register already
    defined. The frame is then not pixel-exact, which is the trade: on the
    same transitions ~1% of a frame's pixels land a mean of 12 off a 441
    maximum, against a picture that was going wrong wholesale.

    Bound it. Borrowing has to mark the register as drawn-with, or the next
    frame redefines it under those very pixels -- and that also takes the
    register out of circulation, so a fade left to borrow without limit walks
    its colours further from the registers they are stuck on with every step, ending in a worse artefact than the recolour it was avoiding. Past SR_BORROW_MAX_D2 a colour takes a register and accepts the recolour
    instead. Measured across the threshold, RGB distance 32 is the knee: 5
    frames recolouring rather than 16 at distance 16, a worst frame of 3
    registers rather than 11, and the error flat across a fade instead of
    climbing.

    Over the whole attract loop that is 5 frames touching a displayed
    register rather than 24, and a worst frame of 3 rather than 37. Games
    that never fill the register map are unaffected, and none of their pixels
    are approximated.

    Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
    --- SBBSecho 3.37-Linux
    * Origin: Vertrauen - [vert/cvs/bbs].synchro.net (1:103/705)