57 Commits
Author SHA1 Message Date
Stenzek efc6ff524b Controller: Produce center for equal opposing half-axis inputs 2026-10-24 14:50:46 +10:00
Stenzek de1cb7225d Cheats: Add override for ForcePGXPPreserveProjectionPrecision 2026-10-24 14:12:16 +10:00
Stenzek d9880a923a Tests: Add PGXP CPU shift, bitwise and ADDI tests 2026-10-24 14:12:16 +10:00
Stenzek b4a9a6b8f2 Tests: Update cheat metadata type 2026-10-24 14:12:14 +10:00
Stenzek d9386a2f83 Qt: Add setting overrides to patch code editor
Also preserves overrides and DisallowForAchievements when a code is rewritten.
2026-10-22 12:54:54 +10:00
Stenzek bf550e7924 CPU/Recompiler: Cancel incoming load delay on a load to the same register
A load in a branch delay slot followed by a load to the same register at the
start of the next block exposed the first value.
2026-10-19 20:34:26 +10:00
Stenzek 37a11f004a Tests: Add register write and coprocessor tests
Ports of general_8_16_32_bit_writes and general_cop_memaccess_jmp, run in each CPU mode.
2026-10-19 18:37:19 +10:00
Stenzek b8e5e9a576 SPU: Clear ENDX on the first sample of the key on delay
Hardware clears ENDX along with the first header fetch, four samples before
the first attack tick, rather than when KON is serviced.
2026-10-19 15:52:08 +10:00
Stenzek 4a8158b445 SPU: Time the repeat address latch from key on
Writing the repeat address stops loop start flags from overwriting it until
the next key on. Hardware fetches the first block's header on each of the
first three samples of the key on delay, so writes before the last fetch are
overwritten and do not latch; later writes latch regardless of pitch or how
long the first block plays.

This replaces the first-block heuristic and removes is_first_block.
2026-10-19 15:52:06 +10:00
Stenzek 805aaf0894 SPU: Model key-on timing and startup delay
Key on/off is only processed on every second sample, and a keyed-on voice
stays silent for four samples before the first attack tick, so ENVX first
changes six or seven samples after the KON write.

Key on clears has_samples, so the remaining delay is only checked before
reading a new block, and voices that are idle or mid-block cost the same as
before. Key off during the delay does not cut it short. IRQ prediction
accounts for the delay before the first block read.
2026-10-19 15:48:46 +10:00
Stenzek 075c8afcab SPU: Decay below the sustain threshold
Require decay to cross the sustain threshold before entering sustain, including
when the threshold is the maximum envelope level. Keep release ending at zero.
2026-10-19 15:48:34 +10:00
Stenzek 1ecd1aa2b1 SPU: Prime the interpolation window on key on
Start the pitch counter at sample index three so the first interpolation window
contains four decoded samples. Add hardware capture regressions for pitches
0x2000 and 0x1500, where ring rotation cannot hide the initial source phase.
2026-10-19 15:48:21 +10:00
Stenzek 1892b879cc SPU: Fix interpolation product precision
Retain one fractional bit in each Gaussian product before accumulation to match
hardware captures. Add capture regressions at unity and fractional pitch, and
update the scalar/SIMD comparison.
2026-10-19 14:31:07 +10:00
Stenzek 0d73ecc483 Host: Remove resource file functions
Use EmuFolders::Resources and FileSystem directly instead.
2026-10-18 22:17:11 +10:00
Stenzek 4b3dafaafa Tests: Fix timers test failures and assertion on shutdown 2026-10-17 14:24:00 +10:00
Stenzek b9b8366406 GPU: Implement v2 textured rectangle flips 2026-10-16 20:44:49 +10:00
Stenzek a9c01a628d GPU: Implement v2 register queries and status bits 2026-10-16 19:12:25 +10:00
Stenzek 050d972a76 GPU: Keep lightgun coordinates in the correct clock domain 2026-10-16 00:00:38 +10:00
Stenzek ac35d7ad8d GPU: Refresh display dimensions when changing deinterlacing 2026-10-16 00:00:13 +10:00
Stenzek a518326745 GPU: Correct fine cropping coordinates and bounds 2026-10-15 23:59:18 +10:00
Stenzek f83e4f6c9c GPU: Reset IRQ and CLUT state correctly
IRQ should be reset on soft reset, and CLUT should be invalidated on
clear FIFO.
2026-10-15 23:54:10 +10:00
Stenzek adcc4c36e9 Timers: Hold sysclk counters after writes and target resets
Counters reset at the target now repeat every target+2 cycles.
2026-10-15 23:50:34 +10:00
Stenzek c012107210 Timers: Toggle IRQ request for both target and overflow in one update 2026-10-15 23:50:34 +10:00
Stenzek 17ce9ad12d Timers: Only toggle IRQ request once in one-shot mode 2026-10-15 23:50:34 +10:00
Stenzek b9d4fc917c Timers: Skip IRQ check when not reaching target or overflowing
CheckForIRQ() was called for all three timers on every update, even
though it only has anything to do when a counter gets to its target or
overflows.
2026-10-15 23:50:34 +10:00
Stenzek 191839abdf Fix regression 2026-10-15 23:50:34 +10:00
Stenzek 436c1e61e5 Timers: Avoid updating counters when reading registers
Updating before the event is due can't raise an IRQ now that it's
scheduled for exactly when the first one happens, so all it changes is
the counters. Reading the counter or mode works out what the counter
would be instead, and only updates when the timer being read reaches
its target or overflows. Reads of GPU-clocked or paused timers don't
need the sysclk timers at all.
2026-10-15 23:50:34 +10:00
Stenzek 5b536b7690 TimingEvents: Add InvokeEarlyNoReschedule()
InvokeEarly() moves the event to its next interval before running the
callback. For the timers this is one tick away, so every register
access moved the event to the front of the queue, only for the callback
to schedule it back to where it was. The new variant leaves the event
alone, and relies on the callback to schedule it.
2026-10-15 23:50:34 +10:00
Stenzek 844961117f Timers: Reschedule CRTC after writing to GPU-clocked timers
The CRTC event is only scheduled for the next IRQ or gate change of the
timers it updates. Nothing redid that after the counter, target or mode
was written, so a closer target or newly enabled sync mode wasn't seen
until the event next ran for some other reason, up to a frame later.
2026-10-15 23:50:33 +10:00
Stenzek 008cd2ac2d Timers: Fix IRQ time for GPU-clocked timers past the target
GetTicksUntilIRQ() said there was no IRQ coming when the counter was at
or above the target, or when the overflow IRQ was used with a resetting
target. The CRTC event wasn't scheduled for these, so they were raised
whenever it happened to run next.
2026-10-15 23:50:33 +10:00
Stenzek ca776d82b0 Timers: Only reach zero target when counter is zero
It was treated as reached every time the counter was updated, including
when no ticks were added, so with the target IRQ enabled any access to
a timer register raised it. Now it's only reached when the counter is
reset by the mode write, and when it wraps around.
2026-10-15 23:50:33 +10:00
Stenzek c71dddf6f5 Timers: Account for overclock remainder when scheduling IRQ
Same problem as the sysclk/8 prescaler, the partial tick left over from
UnscaleTicksToOverclock() wasn't taken off the time until the next IRQ.
2026-10-15 23:50:33 +10:00
Stenzek 2a5f942355 Timers: Account for sysclk/8 prescaler when scheduling IRQ
The partial tick in sysclk_div_8_carry was ignored, so the IRQ fired up
to 7 cycles after the counter reached the target. Since the carry
changes whenever the counters are updated, accessing any timer register
moved the IRQ around as well.
2026-10-15 23:50:33 +10:00
Stenzek 98de9b4a2d Timers: Fix off-by-one when scheduling sysclk event
GetTicksUntilNextInterrupt() was still treating 0xFFFF as the overflow
point, and a counter sitting at the target as about to reach it. Both
cost an extra one tick event, or eight of them with sysclk/8.
2026-10-15 23:50:33 +10:00
Stenzek 4a0746d9fa Timers: Fix target being reached when counter overflows
The counter wasn't brought back into range before comparing it with the
target, so wrapping around always counted as reaching it. This raised
the target IRQ early, toggled the IRQ twice per loop in toggle mode, and
gave the wrong counter value when it was set above a resetting target.
2026-10-15 23:50:33 +10:00
Stenzek 8e7c28987e Timers: Fix sysclk IRQs being delayed by gate changes
SetGate() rescheduled the sysclk event without updating the counters
first when the gated timer was GPU-clocked, so the next IRQ got pushed
back by however long it had been since the last update. Gate changes
that were more frequent than the IRQ stopped it from firing at all.
2026-10-15 23:50:33 +10:00
Stenzek 0ed7e2815c GPU/SW: Add drawing and copy tests
Rectangles and axis-aligned quads are compared against a simple
per-pixel version of the pixel pipeline, clipped triangles against
the same triangle drawn without clipping, and VRAM copies against a
row-by-row copy.
2026-10-15 23:50:32 +10:00
Stenzek 4df2fcc5a6 GPU/SW: Fix source desync in masked VRAM writes
The scalar loop only advanced the source pointer when the destination
pixel was not masked, so every pixel after a masked one was written
with the wrong source data for the rest of the transfer.

The vectorized loop always advances, so this only affected the trailing
pixels of each row, writes which wrap around, and the scalar
implementation.
2026-10-15 23:50:31 +10:00
Stenzek 1f3c4a5c4c Tests: Add MDEC decode tests
Runs RLE streams through the MDEC for each output depth, and compares
the result against a scalar reference decoder.
2026-10-13 15:21:27 +10:00
Stenzek 0a93c2305f Settings: Fix inconsistent default values 2026-10-13 15:21:25 +10:00
Stenzek 60ab60a031 CPU: Don't stall for GTE with a single cycle remaining
Fixes timing of 5 and 8 cycle commands in psxtest_gte.
2026-10-13 15:21:25 +10:00
Stenzek cf71052c40 CDROM: Vectorize XA resampling 2026-10-13 15:21:25 +10:00
Stenzek 22a06c8a40 GTE: Add regression tests
Covers IR/colour saturation, 44-bit MAC overflow wrapping, NCLIP and ORGB
against reference formulas, and hashes the register state after random
instructions through both the interpreter and recompiler entry points.
2026-10-13 15:21:24 +10:00
Stenzek b8ce9b4df4 System: Provide content details to OnSystemStarted()
Avoids the OnGameChanged() call later.
2026-10-13 15:21:21 +10:00
Stenzek d76435ca76 InputManager: Extract internal state to private header 2026-09-25 21:35:44 +10:00
Stenzek 687178a00f InputManager: Internalise private functions 2026-09-25 21:35:44 +10:00
Stenzek e68536dcd7 NeGcon: Create common base class for NeGcon controllers
And move common logic into base class.
2026-09-25 15:25:46 +10:00
Stenzek 62299a5092 LightgunController: Create base class for lightgun controllers
And move common logic into there.
2026-09-25 15:25:46 +10:00
Stenzek ed6720bbf5 Tests: Fix core-tests building on Windows 2026-09-12 22:11:18 +10:00
Stenzek a24350c47c SPU: Decode ADPCM nibbles in pairs
Consume both nibbles from each ADPCM data byte in sequence, halving
loop-control and packed-byte load overhead.
2026-09-12 22:11:17 +10:00