Skip to content

Preserve interlaced fields when drawing GPU primitives - #327

Merged
mstan merged 5 commits into
RetroPortingToolKit:masterfrom
Alexbeav:pr/gpu-interlaced-field-20260906
Sep 7, 2026
Merged

Preserve interlaced fields when drawing GPU primitives#327
mstan merged 5 commits into
RetroPortingToolKit:masterfrom
Alexbeav:pr/gpu-interlaced-field-20260906

Conversation

@Alexbeav

@Alexbeav Alexbeav commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

When 480i drawing prohibits the active display area, raster primitives currently overwrite both row parities. A guest field-detection loop can then stay black at startup. Preserve the selected parity through native-row clipping, restore the caller clip and re-arm precision/perspective metadata on each submission. Fills, copies and transfers remain unmasked. The facade counts each original perspective triangle once, so row metadata re-arms do not inflate diagnostics. No title detection or guest code changes.

Fork review: Alexbeav#22. Cubic completed exact-head check 101479562581 with zero new issues. All earlier review jobs are terminal and findings are resolved in the final source or explicitly reconciled in the replies. The public branch is identical to this reviewed head.

Base 155e269ba5d50fe36523846f908cf124dc1561a0; tested/reviewed head 6fcfb8adbdcd666a2fc8ba419dd4e2aa7ee1faaa; five focused commits; 11 changed files:

  • docs/GPU_INTERLACED_RASTER.md
  • runtime/CMakeLists.txt
  • runtime/include/gpu.h
  • runtime/include/gpu_interlace.h
  • runtime/include/gpu_render.h
  • runtime/include/gpu_sw_renderer.h
  • runtime/src/gpu.c
  • runtime/src/gpu_render.c
  • runtime/src/gpu_sw_renderer.c
  • runtime/src/gpu_vk_renderer.c
  • runtime/tests/test_gpu_interlace_render.c

Runtime files implement the field rule and facade-owned counter; backend metadata setters remain side-effect-free with respect to counting, and backend wide-overlay policy remains unchanged outside field masking; the C fixture tests mode/parity, all nine primitive families, native/4x output, clip restoration, transfers and metadata consumption and logical-triangle counts; CMake registers it; the document describes the invariant and prior behavioral evidence. Source-owned synthetic data only.

Validation on this review head, Windows x64 / WinLibs GCC16.1:

  • Runtime CTest: 69 enabled pass; 2 pre-existing disabled. The initial review head fails 8 added counter assertions. The pre-bounds head fails exactly 2 bounded-row checks while pixel comparisons pass. Both fields at native/4x match unmasked pixel oracles even when precise vertices cross integer bounds. A tiny precise triangle submits 3 row clips instead of 256. A backend that intentionally ignores the clip reproduces 40 wrong field rows on the previous facade. Field-masked flat rectangles now submit one-row geometry, while the ordinary overlay geometry and backend policies stay unchanged. Both parities, no duplicate writes and clip restoration pass. This is a backend-contract fixture, not Vulkan hardware pixel qualification. Focused command: ctest --test-dir <runtime-build> -R gpu_interlace_render_test --output-on-failure.
  • Recompiler suite:58/61 enabled pass;3 disabled. The three failures also reproduce from pristine upstream source: dirty_text_continuation_guards expects an absent source fragment; release_zip expects LF bytes on Windows; aot_overlay_discovery fails its hardcoded MSYS gcc subprocess. Recompiler sources are unchanged by this PR. Python tests ran with PYTHONUTF8=1.
  • Owned Pro Pinball: Timeshock! USA SLUS-00639: fresh process through game frontend, start player game, launch ball, flipper/ball interaction and normal TCP quit at frame 6925. Exact build identifies this head. Digital pad, software/native, existing owned generated game/SCPH5552 code reused unchanged; no emitter-regeneration claim. The title is a private local port, so no public game source or copyrighted payload is attached.
  • Repeat evidence: unchanged exact executable also completed a second fresh player route at frame 6923. One earlier attempt on this head stayed in the startup pixel-test loop through frame 6925 and then exited by TCP request. Its cause is unestablished; a prior-head comparison passed, and the exact edge-pixel synthetic case passes. Do not read the successful repeats as proof that startup is free of intermittent failures. The private staging failure in a separate control never launched a runtime and is excluded.
  • Current upstream runtime does not compile with public recomp-ui/master773155ae: unrelated new lobby/spectator fields are missing. Retail qualification therefore uses supported PSX_RECOMP_UI=OFF, direct runtime launch into the game frontend. This is not launcher compatibility acceptance.

Field selection uses the existing vertical-blank latch, not scanline-accurate timing. Row clipping can increase hardware submissions; the separate #326 addresses GL readback volume. No Vulkan-wide, netplay, full-game, all-audio or save/load acceptance is claimed. Runtime-only consumer pin update is required; no game regeneration is required by this correction.

Developed with AI assistance; validated as described (test evidence in PR body). AI writes the code and the PR, but I always test before I send something up. Happy to iterate on this process with your feedback.

mstan added a commit that referenced this pull request Sep 7, 2026
@mstan
mstan merged commit b775d3e into RetroPortingToolKit:master Sep 7, 2026
@mstan

mstan commented Sep 7, 2026

Copy link
Copy Markdown
Member

@Alexbeav I've opened #336 to roll back this PR in commit 24c6c56, after tying the retail SCPH1001 BIOS-screen stall to 0661ce77 with matched Ape Escape builds.

The per-row primitive resubmission/clip changes amplify an existing malformed DMA list into enormous GL work. A separate CPU/DMA ownership experiment fixes the packet race, but it needs VHD/Spot compatibility coverage, so it is not bundled into this rollback.

#336 reverts only #327's five commits and preserves #326/#328. The rollback reaches Ape's title/menu and frame 11669 on retail BIOS; OpenBIOS also boots. MMX6 retail boot passes and closes normally at frame 4123. Eight focused tests pass, and the retained GL readback fixture passes all 71 checks at 1x and 4x.

This temporarily restores the previous interlaced-field limitation. A replacement should avoid per-scanline backend draw/flush multiplication and include windowed retail SCPH1001 boot in validation. Full attribution and scope are recorded in #336's investigation document.

mstan added a commit that referenced this pull request Sep 7, 2026
Revert #327 interlaced row submission to restore retail BIOS boot
Alexbeav pushed a commit to Alexbeav/psxrecomp that referenced this pull request Sep 10, 2026
…e retail BIOS boot

Matched Ape Escape retail SCPH1001 LLE builds identify 0661ce7 as the visible boot regression: parent 155e269 reaches game code, while 0661ce7 stalls near BIOS frame 375. Revert its four dependent follow-ups too; retain PR RetroPortingToolKit#326 readback bounds and PR RetroPortingToolKit#328 Vulkan aspect changes.

The row-by-row raster dispatcher amplifies an existing malformed DMA list into massive GL work. Keep the broader CPU/DMA arbitration experiment separate for compatibility testing. Document attribution, validation, and the temporarily restored interlace limitation.

Validation: full Ape target reaches title/menu and frame 11669 on retail LLE; OpenBIOS control reaches frame 3701. Eight focused tests pass; retained GL readback fixture passes 71 checks at both 1x and 4x after linking local SDL with iconv. Beads: beads-iisy; DMA follow-up: beads-eio.3.122.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants