Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs/WIDESCREEN_PATTERNS.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,26 @@ and must equal the reflected source column; mid-scroll the margin must equal
what the tilemap authors there (i.e. must be byte-identical to the natural
render), which is the assertion that catches a viewport-space fold.

Reflection also copies dynamic changes. If an arena can destroy its interior
floor, use `PpuSetWidescreenLayerWorldRepeatBand` to repeat a short undamaged
strip at each world edge instead. All authored room columns, including real
offscreen damage, and every native column remain unchanged. This keeps a
floor pit or entrance from being duplicated outside the room. Width0 disables
the band; larger widths are bounded by the authored span. As with reflection,
the source strip must be in the rendered line.

Finite object canvases need a different source rule from scenery. X3's Maoh
paints its BG2 body over a reused circular map: neighboring map entries still
contain old level tiles. A complete map is not necessarily a complete authored
canvas. `WsShadowUseFilteredVram(layer, ppu, filter, context)`, registered after
`WsShadowFrame`, lets a title retain the renderer's current object entries and
omit known unrelated entries in the margins. It reads the exact live tile and
map address, bypasses terrain history, and leaves native and edge-straddling
chunks untouched. Registration expires next frame. Combine it with a world
clip if wrapping the map could repeat the object; supply skyline and terrain
from their own layers. Qualify the character range from the actual game data,
including moving/destroyed pieces, rather than guessing from a screenshot.

### P2c. A continuous status bar anchors its rigid groups and stretches only elastic material

**Defect:** `PpuSetWidescreenLayerAnchorBand` moves a raster status bar's left
Expand Down Expand Up @@ -192,6 +212,30 @@ destination run; and the gauge sweep -- every `k` from 0 to `n`, both gauges,
within 1px of `round(k*dw/n)` of each other and of the ideal.
`tests/ppu/ppu_elastic_band_test.c`.

### P2d. A view can slide inside room bounds without moving the guest camera

`PpuSetWidescreenViewAnchor` and `PpuSetExtraSideSpace` let a consumer
allocate its total horizontal expansion to the open side of a room. The
physical frame origin follows the live margins. Native background and OBJ
coordinates stay unchanged; HUD groups keep their screen positions. Clear
padding when a room cannot fill the requested span. The policy resets each
frame and stays outside guest save-state spans.

This mechanism reuses the accepted, parked X1 experiment `c3dc50a` with its
physical-centre HUD correction. The parked X1 worktrees remain untouched.
Consumers must validate their own camera bounds, streaming and spawn envelope;
this engine change does not enable anchoring for any title automatically.
`ppu_view_anchor_test` checks actual image placement, both edges, narrow rooms,
HUD, native/default-off output, reset and storage boundaries. Priority buffers
reserve the entire maximum expansion on either side: `kPpuMaxFrameExtra` caps
the symmetric output budget at 272 and `kPpuLineBorder` is the signed-column
storage origin. The old `kPpuExtraLeftRight` name remains an origin alias so
existing line enhancers keep indexing the same native columns. Presented
frames remain capped at 800 pixels. The 684/800 tests use independent 256px
renders as their oracle, including both extremes and physical HUD placement.
Ordinary 9-bit OBJ coordinates still require title-owned positioning/hints;
larger background buffers alone do not establish ultra-wide sprite coverage.

### P3. Periodic layers fold; world-anchored layers use history

**Defect:** treating a horizontally periodic layer (sky, repeating city glow) as
Expand Down Expand Up @@ -258,6 +302,20 @@ uint16 WsOamXReject(uint16 x_plus_16, uint16 widened_limit) {

The PPU's 9-bit OAM X path already renders negative and 256+ coordinates.

For anchored views wider than512 columns, nine bits cannot identify every
screen coordinate. X3 retains the full X computed by its original HG51B
microcode through `cx4_set_ram_write_observer`, then attaches it to the actual
OAM XY upload through `dma_set_oam_xy_notify_hook` and `PpuWsSetOamFullX`.
The PPU uses it only when explicitly enabled and its low nine bits still
match guest OAM. Ordinary XY writes invalidate it. Titles must serialize both
pending producer coordinates and uploaded coordinates in their state extension,
which also participates in rollback. This observes original execution; it does
not replace the sprite builder or change guest OAM, camera or sequence state.

Keep the viewport budget at least16 bits through the host-to-PPU call. A
272-column budget cast to eight bits became16 and collapsed800px output to288.
The built X3 regression checks actual684/800px images, not just buffer sizes.

**Check:** an enemy must remain drawn while straddling both margin edges, not just
the right one.

Expand Down
74 changes: 74 additions & 0 deletions docs/validation/mmx2-rocket-serges-margins-2026-10-26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# X2 rocket and Serges margin follow-up

The rocket ride exposed uniform terrain being rejected, physical scroll aliases
being interpreted as 1024px maps, and mode2 offset-per-tile drawing bypassing the
world source. The resolver now accepts self-validated uniform BG1 terrain while
retaining the moving-object BG2 safeguard, uses the actual 512x256 map aliases,
and receives effective raster/OPT offsets from the mode2 drawing path. X2 also
uses the existing OAM-only HUD anchor so BG3 scenery is no longer displaced.

Serges's authored room ends at world X0B80. Continue only its BG1 backdrop beyond
that boundary while the original camera is locked and the machine is resident.
The title supplies this room selection; the shared provider offers an optional
right boundary and a margin-only override. Native pixels always retain VRAM,
and the real left-side scenery/door remains visible at wider aspects. BG2 and
OAM, including the moving machine, pilot and platforms, are not repeated.

Two follow-ups address the remaining owner observations. During Ostrich's
entrance, BG2 is a complete circular parallax canvas. Raster scrolling selects
world X768 where the finite layout contains black padding, although VRAM
already holds the correct scenery. The title selects actual VRAM for this
layer in the destination arena; the rocket ride retains its streaming source.

Serges's complete front is already in the live BG2 layout at local Y1024.
Before it enters the native view, the almost-empty native samples reject that
source under the general moving-object safeguard. The original streamer has
not yet uploaded the lower cannons into the widened edge, so VRAM fallback
shows an incomplete front. Select this known loaded source canvas while the
original background actor and camera lock are active. Native validation still
applies; only gutters use the live map, including destruction edits. Parent
position, entrance duration, collision and result flags are untouched.

Validation uses private muted profiles and verified unmodified USA ROMs:

- The actual rocket control/camera ascent and original arena handoff complete
over 780 frames at hybrid342 and interpreter684. No audited result flags are
written. Same-width before/after samples agree in full WRAM and VRAM.
- All 24 cropped native-view samples agree outside the relocated HUD. One
cross-width arena sample has a differing scratch byte at WRAM10; full
cross-width RAM identity is not claimed.
- Serges entrance replays at hybrid342, hybrid684 and interpreter684 alter only
the right gutter. All native/left pixels, full WRAM and VRAM agree with the
prior build in 21 samples per configuration. Current-build save/load agrees
in all RAM and pixels at342 and684.
- Production C tests cover aliasing, uniform terrain, dynamic object rejection,
margin-only precedence over uploads, preservation of native pixels and the
left source, and clearing the optional boundary for ordinary rooms. Actual
mode2 composition and inactive-provider rendering checks also pass.
- Accepted X3 factory and Byte replays retain all sampled pixels and WRAM
through the rocket update. The optional boundary defaults to zero for X3.
- Short serial software/debug samples showed about235..256fps versus
baseline236..249fps. These establish headroom, not release frame-time parity.
- Ostrich entrance:20 samples over300 frames per width at342 and interpreter684
remove the rectangles with identical native pixels, full WRAM and VRAM.
Current-build save/load agrees in all RAM and pixels at both widths, and the
actual780-frame rocket/ascent handoff still passes with the VRAM policy.
- Serges canvas:30 samples over360 frames per width at342 and interpreter684
show the complete front in the gutters with identical native pixels, full
WRAM and VRAM. Current-build save/load agrees in all RAM and pixels at both
widths and in the exposed phase. Destroyed cannons remain absent. Production
tests exercise sparse canvas selection, native mismatch rejection, live map
edits, native pixel preservation, fresh blank uploads and ordinary-room reset.
- The combined canvas policies retain all sampled342px presented pixels and
all128KiB WRAM in the accepted X3 Byte420-frame and factory360-frame replays.

The original-ROM arena reference is valid. Unsuccessful original rocket and
Serges preparation attempts are excluded. The owner accepted the rocket/ascent
visuals, Serges backdrop, Boss Rush black bars, exposed Serges weakpoint and
complete stage exit in round5. Byte, doors and factory are also accepted and
require no repeat owner handoff. The two follow-up visual fixes (Serges front
and Ostrich entrance bars) await focused owner confirmation. Remaining fortress
and final routes, the full content inventory, independent audio qualification
and current-main combined integration remain open. Nothing is merged here.

Evidence: `G:/Temp/Codex/mmx23-trigger-audit-20261026/burndown`.
33 changes: 33 additions & 0 deletions docs/validation/mmx23-door-faces-2026-10-26.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# X2/X3 door presentation

X1 already selected the boss-door column facing the camera's current room.
Port that structural rule to the shared X2/X3 exact background source. The
outward-facing duplicate samples the adjoining wall. Require all three
mirrored metatiles and distinct cap/body characters; X2's symmetric wall
decoration is a negative fixture, not a second door style.

The world provider can explicitly return a presentation override. Only BG1
opts into native-region overrides. Ordinary exact results preserve native
VRAM and recent game writes; a hidden door face must also suppress recent
uploads of that face during animation. Other world-provider consumers retain
their existing behavior.

Validation in the paired X2/X3 trace builds:

- Production C tests cover measured X2/X3 door words, rejection of the similar
wall, native pixel identity and explicit override precedence over game writes.
- X2 Serges approach and interior show one face per doorway on both sides.
- X3's 400-frame entry/open/cross/close sequence was sampled every four frames
against a simultaneous native-width replay. Excluding relocated HUD pixels
and precisely the hidden 16-pixel face, all 100 frames match: zero other
differing pixels, including the retained animated door face.
- Continuous and save/load branches match WRAM and every output pixel through
the X2 door crossing and X3 crossing/intro. The title load callbacks reset
unsaved presentation history rather than retaining the abandoned timeline.
- X2's muted, unthrottled software/debug build advances about 227 frames/sec
in the measured doorway scene. This measures simulation headroom, not a
display frame-time benchmark.

Private ROM/state evidence: `G:/Temp/Codex/mmx23-trigger-audit-20261026/feedback3`.
The broader audits and owner acceptance remain open. This does not qualify the
previously reported X2 rocket margins or Serges entrance artwork.
3 changes: 2 additions & 1 deletion runner/runner.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,8 @@ set(SNESRECOMP_RUNNER_SOURCES
# it, authored from this core's observed behavior.
#
list(APPEND SNESRECOMP_RUNNER_SOURCES
${SNESRECOMP_RUNNER_ROOT}/src/snes/cx4.c)
${SNESRECOMP_RUNNER_ROOT}/src/snes/cx4.c
${SNESRECOMP_RUNNER_ROOT}/src/snes/mmx23_background.c)
message(STATUS "Cx4: instruction-level HG51B S169 core (ares, ISC)")

# ── Windows: UTF-8 process code page ──────────────────────────────────────
Expand Down
Loading
Loading