Skip to content

Improve SmackDown 2 runtime stability, audio, and Vulkan performance - #16

Closed
shaneomac1337 wants to merge 7 commits into
mstan:masterfrom
shaneomac1337:smackdown2-fixes
Closed

Improve SmackDown 2 runtime stability, audio, and Vulkan performance#16
shaneomac1337 wants to merge 7 commits into
mstan:masterfrom
shaneomac1337:smackdown2-fixes

Conversation

@shaneomac1337

Copy link
Copy Markdown
Contributor

What changed

  • fixes recompiler boot/discovery gaps and overlay-loader hot-path overhead
  • adds PSX SPU Gaussian interpolation and reverb support
  • improves Vulkan frame delivery with coalesced command submission and reusable staging buffers
  • prefers mailbox presentation for frontend-paced tear-free output
  • adds Vulkan CRT/composite/Trinitron presentation shaders and launcher selection
  • includes Windows framework build and regeneration helpers

Why

SmackDown 2 previously encountered boot freezes, missing reverb, and Vulkan frame-time spikes caused by repeated command submissions, staging allocations, and competing presentation pacing.

Impact

The game boots reliably, retains higher-quality PSX audio, and renders through Vulkan at a much steadier cadence while preserving configurable screen simulation.

Validation

  • regenerated the SmackDown 2 static recompilation output
  • rebuilt SmackDown2Recomp.exe successfully with Vulkan enabled
  • exercised Vulkan diagnostic captures at a stable 60 fps

The generic BIOS-only framework link still reports the existing unresolved psx_game_address_in_text symbol; the game target itself builds successfully.

shaneomac1337 and others added 7 commits July 12, 2026 16:53
- psx_cyc.h / psx_cycles.c: _BitScanForward/_BitScanReverse shims for
  __builtin_ctz/__builtin_clz under _MSC_VER
- full_function_emitter.cpp / main_psx.cpp: emit a portable .CRT$XCU
  init-pointer instead of GCC-only __attribute__((constructor)) in
  generated dispatch/game code
- main.cpp: declare cross-language globals extern "C" so MSVC links
  them against their C definitions (no-op for GCC/Clang)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two deterministic boot hangs (WWF SmackDown! 2, SLUS-01234):

1. overlay_loader_dispatch()/is_candidate()/call_native() ran during
   early BIOS kernel init (0xBFC0DB10 memcard polling loop) before
   overlay_loader_init() built the range-index structures, walking
   uninitialized lists until a PC=0 trap (froze at cycle 208195 every
   boot). Guard all three entry points on s_active.

2. Code at 0x800D1F28 (boot-text populated by bulk host transfer that
   bypassed the RAM write-marking hooks) was neither compiled, dirty,
   nor overlay -> unknown-dispatch fail at frame 1340. Add a fallback:
   an address above overlay_region_floor whose word decodes as valid
   MIPS is marked executable and handed to the dirty-RAM interpreter.

Validated 5/5 reproducible boots, 2000+ frame sustained runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Replace nearest-sample voice pitch resampling with the PS1 hardware
  4-tap Gaussian (No$ table, new spu_gauss.h; formula
  (g[0xFF-i]*s[-3] + g[0x1FF-i]*s[-2] + g[0x100+i]*s[-1] + g[i]*s[0])>>15
  with i=(phase>>4)&0xFF). Nearest-sample put a flat aliasing shelf at
  ~-31 dB across 8-22 kHz (measured); Gaussian drops it 18 dB and
  restores natural spectral decay. Adds prev[3] cross-block history.
- Beetle-model reverb engine on the SPU mix.
- Gate the float-shadow substitution off while any voice has a reverb
  send (the shadow models only the dry mix).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The PS1 GPU does not render a polygon or line when the distance between
any two vertices exceeds 1023 horizontally or 511 vertically (No$ docs;
Beetle/DuckStation enforce it per rendered triangle). Games rely on the
cull during zoom transitions and close camera cuts: their 11-bit-wrapped
vertices span the whole coordinate space and, without the reject, get
rasterized as giant flat-color triangles covering the frame (SmackDown 2
rendered its menu star wipe and in-match crowd cuts as a full black
cover in both the software and GL backends).

Applied per-triangle in all polygon execs (quads reject each half
independently; textured variants still latch the texpage word first,
matching hardware), plus lines and both polyline continuations.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fixes found chasing block corruption on AMD RDNA3 (RX 7900 XT) that the
NVIDIA driver this backend was developed on tolerates:

- flush_cpu_upload: keep every packed rect's VkBufferImageCopy
  bufferOffset 4-byte aligned (an odd w*h rect misaligned every
  following rect's R16 offset to 2 mod 4)
- begin_geo_pass + wide passes: color-aspect self-barrier mirroring the
  existing stencil self-barrier (img_to emits no barrier when the layout
  is unchanged, and the render pass declares no EXTERNAL dependency, so
  back-to-back passes had no memory dependency on the color attachment)
- submit_present: wait the acquire semaphore at TRANSFER (all swapchain
  writes here are transfer ops); waiting at COLOR_ATTACHMENT_OUTPUT left
  them unordered against presentation-engine release

Still NOT fixed on AMD: black block confetti on BIOS/FMV screens.
VRAM-state dumps prove the hr image content is bit-perfect at present
time, so remaining corruption is in the present chain. Env-gated
diagnostics (tagged [DEBUG-vk01]) included for the ongoing hunt:
PSX_VK_VERIFY / PSX_VK_DUMP / PSX_VK_ONEPASS / PSX_VK_EAGER_UPLOAD /
PSX_VK_NO_MERGE.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mstan

mstan commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Hello!. I have pulled the MSVC generated-initializer fix into #1 and the overlay pre-initialization guardinto #23

The broader executable discovery, GPU/SPU changes, Vulkan work, and shaders are not yet pulled in. I need to give those more of my time before I can merge them out.

But thank you for the work so far! Eager to find time to dig into the rest

@mstan

mstan commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Tested the extracted Vulkan changes from this PR in Tomba 2 on an RTX 3080 Ti. It booted through SCEA and the Whoopee Camp FMV into gameplay, but it does not feel merge-ready yet:

  • Performance was poor.
  • Some 3D terrain/model geometry fluctuated in place.
  • The Blackjack HUD at bottom center showed 3 icons when it should show 1.

Keeping the Vulkan work parked for further isolation.

mstan added a commit that referenced this pull request Jul 15, 2026
Port the reusable Gaussian interpolation slice from PR #16 while keeping its reverb engine on a separate branch.

Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@mstan

mstan commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Hello! Wanted to follow up on this draft. The SPU reverb implementation closely seems to model Beetle/Medafen's, which are GPLv2. Want to make sure before I include anything that I understand attribute.

Similar question for the CRT shader. Suggest it's inspired by CRT-Royale. I'm not sure what that is, and would like to understand its licensing as well before taking it into consideration.

Take care!

@mstan

mstan commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Following up. The Vulkan work was ultimately a net positive. Very performant, but still suffers from some visual fidelity issues.

In Tomba 1, a lot of sprites had some garble. In Tomba 2, the HUD item selector was showing hidden element that's normally toggle in. There was also some items poking through terrain.

I'll go ahead and accept the work, but will not be making Vulkan an exposed option yet until these types of bugs are ironed out.

With regards to the remaining unmerged items; license concerns remain outstanding. Given that this PR is somewhat stale and the artifacts are independent items anyhow, I'll go ahead and close this draft PR. Please submit any follow ups as individual items, please!

Tomba__Recompiled_4LTYSNboF9 Tomba2Recomp_NKRcSY4bwZ Tomba__Recompiled_kG2hMx3gjw

Thank you for the contributions!

@mstan mstan closed this Jul 21, 2026
OpokXeno pushed a commit to OpokXeno/psxrecomp that referenced this pull request Jul 22, 2026
Record that PR mstan#61 reconstructed the reusable Vulkan work from Martin Penkava's PR mstan#16 branch.

Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
fabioap-cpu pushed a commit to fabioap-cpu/Tekken1Recomp that referenced this pull request Jul 30, 2026
Adapt only the fail-closed overlay lifecycle checks from mstan/psxrecomp#16 commit e6809ccf7d778a4c2f32d9e27c0ec31a44cbd2ba. Add a focused structural regression test and record the excluded dirty-interpreter and game/runtime work.

Co-authored-by: Martin Penkava <mpenkava1337@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
@mstan

mstan commented Aug 6, 2026

Copy link
Copy Markdown
Owner

A follow up on this PR. PR #104 introduced a clean room psx-spx/nocash register instead. One thing that was not addressed in that was the hardware's 22.05->44.1 kHz reverb reconstruction filter. Given Beetle's GPL licensing, I wasn't able to borrow it from there and would need to derive a clean room implementation. The functionality is isolated and a future PR that modifies it is always welcome; assuming it follows proper licensing.

ClaudioVarandas pushed a commit to ClaudioVarandas/psxrecomp that referenced this pull request Aug 18, 2026
…inational

Closes the four gaps named in issue mstan#103 and lands the separable, verified
parts of PR mstan#102. See docs/internal/SPU_FIDELITY_103.md for the per-piece
disposition and the oracle-verification queue.

SPU DSP (issue mstan#103), clean-room from hardware documentation:

- Reverb: the documented 22050 Hz engine — vLIN/vRIN input, same-side and
  crossed different-side IIR reflections, 4-tap comb early echo, both
  all-pass filters, vLOUT/vROUT output, and the work-area address advance.
  Gated on SPUCNT bit 7 for WRITES only; reads, IRQ checks, address advance
  and output always run, as on hardware. Addressing is confined to
  [mBASE, 0x80000). Per-voice sends from EON, CD send from SPUCNT bits 0+2.
- Noise: 16-bit LFSR with the documented parity feedback, clocked at the
  SPUCNT bits 8-13 rate; NON voices substitute it for their ADPCM sample.
- Volume sweeps: all 24 voice L/R plus main L/R. Bit 15 selects sweep vs
  direct; sweep is a live envelope on the same rate machinery as ADSR, and a
  guest read of a sweeping register returns the live level.
- Capture buffers: CD L/R and voice 1/3 output written to SPU RAM, so a game
  that parks the IRQ address there still gets its interrupt.
- SPU IRQ (I_STAT bit 9): checked at every SPU RAM access class — FIFO, DMA
  both directions, ADPCM block fetch, capture writes, reverb work-area
  accesses — gated on SPUCNT bit 6, mirrored in SPUSTAT bit 6, acked by
  clearing SPUCNT bit 6.

The CD-only fast path in spu_render was removed rather than extended: the
SPU now has per-frame work that must run in every path, and an FMV (XA audio
with zero active voices) is exactly the CD-with-reverb case.

This is a clean-room implementation from the psx-spx/nocash register map and
documented algorithm. Beetle's source was deliberately not consulted: it is
GPL-2.0-or-later and this project is PolyForm Noncommercial. PR mstan#16 was
parked for exactly that reason and PR mstan#13's reverb was separately wrong (it
gated on bit 15 of dAPF1, an address offset, instead of SPUCNT bit 7). The
one place this knowingly deviates from hardware is the 22.05 -> 44.1 kHz
reconstruction filter, which the documentation does not specify; it is
isolated in a single function and flagged for oracle comparison.

CAUSE.IP2 (from PR mstan#102):

IP2 is combinational on R3000A — it mirrors the interrupt line and falls the
instant the guest acks I_STAT or masks the source. It was being OR'd in at
delivery and never cleared, in TWO places (the compiled path and
psx_interpreter.c, the latter missed by PR mstan#102), leaving a phantom pending
interrupt that can spin a kernel dispatcher looping on CAUSE.IP & SR.IM.
psx_irq_refresh_cause_ip2() is now the sole writer of bit 10, refreshed at
raise, I_STAT ack, I_MASK write, HLE context restore and power-on. Verified
against the Beetle oracle's irq.cpp/cpu.cpp rather than asserted, and
covered by test_cause_ip2_combinational.

Mid-dispatch audio pump (from PR mstan#102), with a fix: routed through a gate
that mirrors sdl_audio_update's mute/sink decision. Pumping unconditionally
from the VBlank edge, as submitted, would have pushed real audio during every
turbo-load hard mute and defeated the freeze-in-place mute model.

SPU RAM DMA readback (from PR mstan#102): DMA4 in the SPU->RAM direction wrote
literal zeros; SPU RAM is readable memory and titles carry state through it
across an Exec boundary.

Also fixes an unrelated build race found on the way: tools/embed_spirv.py
wrote its intermediate SPIR-V to <source>.spv, so the two runtime targets
that embed the same shaders raced on one path and one deleted the file the
other was reading.

Co-Authored-By: Alexandros Mandravillis <Alexbeav@live.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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