Skip to content

Add nxdoom linum - #3681

Merged
xiaoxiang781216 merged 1 commit into
apache:masterfrom
JorgeGzm:add_nxdoom_linum
Jul 30, 2026
Merged

Add nxdoom linum#3681
xiaoxiang781216 merged 1 commit into
apache:masterfrom
JorgeGzm:add_nxdoom_linum

Conversation

@JorgeGzm

@JorgeGzm JorgeGzm commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

The NXDoom blit assumed a 32-bit frame buffer. It wrote a uint32_t per pixel
and converted the palette with ARGBTO32 as it went, so the image came out
wrong on anything else. It also drew at the origin, leaving the image in a
corner of a display it does not fill, and indexed the source by the output
column, which costs an integer division for every pixel of every frame.

The palette is now converted once per palette change into the format the frame
buffer actually reports, output columns are mapped to source columns through a
table built at startup, and the result is centred. Output rows that come from
the same source row are copied rather than converted again.

Four options are added, all disabled by default, so a board can trade memory
for speed where it pays:

  • GAMES_NXDOOM_FB_CMAP: blit palette indices and let a frame buffer that has
    a colour map do the conversion in hardware while it scans out.
  • GAMES_NXDOOM_FILLSCREEN: stretch over the whole display rather than
    scaling by a whole number.
  • GAMES_NXDOOM_ROWSTAGE: build each row in a staging buffer so the frame
    buffer only sees burst-friendly copies.
  • GAMES_NXDOOM_STATIC_SCRNBUF: place the render target in .bss, keeping it
    out of external memory on a board whose heap is mostly that.

The frame buffer is also now opened with O_CLOEXEC.

Impact

  • Users: the four new options default to n, so a build that does not
    enable them takes the same path as before. One behaviour changes for
    everyone: the image is now centred rather than drawn in the corner of a
    display it does not fill (no change where it fills exactly, such as the
    simulator).
  • Build: no new dependencies.
  • Hardware: frame buffers of 8, 16, 24 and 32 bits per pixel are now
    handled; previously only 32 worked.
  • Compatibility: for the previously working case (32 bpp, whole-number
    scale) the output is unchanged. colmap[x] = x * 320 / outw was verified to
    equal the old x / scale for every column at every scale from 1 to 8 (zero
    differences), and the palette table uses the same ARGBTO32.
  • Security: none.

Testing

Host: Linux x86_64.
Boards: LINUM-STM32H753BI (1024x600 LTDC panel, frame buffer in SDRAM), and
the simulator.

nxstyle reports 0 warnings on games/NXDoom/src/i_video.c. Builds are
warning-free.

This branch was also built against a nuttx tree with the companion change
reverted, to reproduce what CI does (each repository is built against the
other's master). sim:nxdoom builds clean, confirming this PR has no
cross-repository dependency.

Regression, existing configurations:

configuration geometry result
sim:nxdoom, no new option enabled 1920x1200, 32 bpp, scale 6 builds and runs
raspberrypi-4b:nxdoom, no new option enabled 1920x1080, 32 bpp, scale 5 builds, 0 warnings
sim set to the Raspberry Pi 4B geometry 1920x1080, 32 bpp, scale 5 builds and runs
linum-stm32h753bi:nxdoom, all options on 1024x600, 8 bpp CLUT builds and runs

Both existing configurations were built with none of the new options enabled,
which is the path they take by default.

The Raspberry Pi 4B is the case where the image does not fill the display: its
frame buffer is 1920x1080 at 32 bpp, so DOOM is scaled by 5 to 1600x1000 and is
now centred rather than drawn in the corner. I have the board's toolchain but
not the board, so in addition to building it I reproduced its geometry in the
simulator and ran the game there, which exercises the same non-filling, centred
path.

Simulator run, no new option enabled:

                            DOOM Shareware
i_init: Setting up machine state.
m_init: Init miscellaneous info.
r_init: Init DOOM refresh daemon - [                   ]...................
p_init: Init Playloop state.
hu_init: Setting up heads up display.
st_init: Init status bar.

Effect of the options, measured on the LINUM board at 1024x600 with a frame
counter added temporarily to i_finish_update(), playing the same attract-mode
demo:

ROWSTAGE STATIC_SCRNBUF frame rate
off off 5.1 fps
off on 6.5 fps
on off 8.4 fps
on on 13.7 fps

The blit assumed a 32-bit frame buffer:  it wrote a uint32_t per pixel
and converted the palette with ARGBTO32 as it went, so the image came
out wrong anywhere else.  It also drew at the origin, leaving the image
in a corner of a display it does not fill, and indexed the source by the
output column, which costs a division for every pixel of every frame.

Convert the palette once per palette change into the format the frame
buffer actually uses, map output columns to source columns through a
table built at startup, and centre the result.  Output rows that come
from the same source row are copied rather than converted again.

Four options are added, all off by default, so that a board can trade
memory for speed where it pays:

  GAMES_NXDOOM_FB_CMAP blits palette indices and lets a frame buffer
  that has a colour map do the conversion in hardware.

  GAMES_NXDOOM_FILLSCREEN stretches the image over the whole display
  rather than scaling it by a whole number.

  GAMES_NXDOOM_ROWSTAGE builds each row in a staging buffer so that the
  frame buffer only sees burst-friendly copies.

  GAMES_NXDOOM_STATIC_SCRNBUF places the render target in .bss, which
  keeps it out of external memory on a board whose heap is mostly that.

On an STM32H753 driving a 1024x600 panel from SDRAM, the last two are
worth 2.7x together.

Also open the frame buffer with O_CLOEXEC.

Signed-off-by: Jorge Guzman <jorge.gzm@gmail.com>
@JorgeGzm

Copy link
Copy Markdown
Contributor Author

This PR is being tested with PR apache/nuttx#19579

@xiaoxiang781216
xiaoxiang781216 merged commit 07c1234 into apache:master Jul 30, 2026
40 of 41 checks passed
@JorgeGzm
JorgeGzm deleted the add_nxdoom_linum branch July 30, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants