Commit Graph
50615 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 746ddfa818 docs: How lag sync paces, and how to benchmark it on a platform
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:19:56 +01:00
Henrik RydgårdandClaude Opus 5.5 c0826fab63 Lag sync: Sleep without spinning, and burst when the host is nearly flat out
Lag sync waited with sleep_precise, which on Windows spins the last
millisecond, so its 1 ms waits were nearly all spinning. It now sleeps
with a new sleep_approx (no spin), only once 2 ms or more ahead, and asks
for as much less as the OS has been waking it late. Being late doesn't
add up, since the goal is measured from a fixed base.

Pacing every millisecond only pays with time to spare. Each second, the
share of wall time spent waiting (in lag sync or in the frame throttle)
is measured. Under 10%, it falls back to bursting with the frame
throttle, as without lag sync, and goes back after two seconds over 25%.

GTA VCS on an M1, at --speed values around the host's limit, now runs
as fast as without lag sync or slightly faster. At 1x it costs about 1%
of a core in cycles over bursting, the same as before.

Headless --frame-stats prints lag sync's sleeps, lateness and fallbacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 12:19:55 +01:00
Henrik Rydgård b915046842 Merge pull request #23024 from hrydgard/granular-target-like-classic
Audio: Make smooth audio use similar buffersizes to classic audio. Show stats.
2026-11-10 12:19:38 +01:00
Henrik Rydgård 5fc7f4b957 Default audio playback mode to smooth. 2026-11-10 10:37:59 +01:00
Henrik RydgårdandClaude Opus 5.5 e040fa5223 Audio: Show granular mixer stats in the audio debug overlay
Queue fill and cap (in granules and ms), under/overruns, output rate, read
size and frame time, replacing the "no stats yet" placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:29:23 +01:00
Henrik RydgårdandClaude Opus 5.5 5f349fd603 Audio: Size the granular queue from the classic resampler's target
The queue cap was four output callbacks plus a frame of audio. Bluetooth and
other outputs without a fast path call back with large chunks, so that came
to about 100 ms there. Now it's the classic target (which also honors Extra
audio buffering), raised for slow games' per-frame bursts and to keep half
the queue above one callback's read, plus a granule for the overlap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:29:23 +01:00
Henrik RydgårdandClaude Opus 5.5 997cc92072 ImDebugger: Count a queued granule as half a granule of latency
The granules overlap by half, so each one in the queue adds 128 samples, not 256.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 10:29:23 +01:00
Henrik Rydgård d20d388611 Merge pull request #23020 from hrydgard/god-eater-dlc
Loader: Don't boot a game update that isn't newer than the disc
2026-11-10 01:00:21 +01:00
Henrik RydgårdandClaude Opus 5.5 44ba2a1c93 Loader: Don't boot a game update that isn't newer than the disc
Since we started booting PSP/GAME/<DISC_ID>/PBOOT.PBP, a modified disc that
has the latest update built in (with its APP_VER raised to match) gets its
executable replaced by the stock update's. With fan translations, that runs
the untranslated executable, which can reject the translated data files.

Only boot the update when its APP_VER is higher than the disc's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 00:38:48 +01:00
Henrik Rydgård 3a85ec9fae Merge pull request #23019 from hrydgard/gta-pause-flash
GPU: Don't estimate a first-frame safe size for screen-sized buffers
2026-11-10 00:33:25 +01:00
Henrik Rydgård 2f4bd6b9d0 Merge pull request #23017 from hrydgard/android17-adrenotools
Android: Stop linkernsbypass from running at load; no custom drivers on 17+
2026-11-09 22:48:07 +01:00
Henrik Rydgård d6c4cc55a1 Merge pull request #23016 from hrydgard/more-ui-fixes
Debugger input fixes, and a corrected port offset hint
2026-11-09 22:34:22 +01:00
Henrik RydgårdandClaude Opus 5.5 c2340b1cb3 Declare VulkanCustomDriverAllowedByOS() in the Vulkan-free header
DriverManagerScreen.cpp included VulkanLoader.h, which pulls in X11 on
Linux, whose Screen typedef clashes with our Screen class.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 22:30:59 +01:00
Henrik RydgårdandClaude Opus 5.5 8de4bcd797 Android: Stop linkernsbypass from running at load; no custom drivers on 17+
Google reports PPSSPP crashing at startup on Android 17 internal builds,
in linkernsbypass (part of libadrenotools), whose constructor walks
libdl's dlopen to find the linker's internal __loader_dlopen. It ran on
every launch, custom driver or not.

Switch libadrenotools to the hrydgard fork, where linkernsbypass resolves
those symbols on first use, so only users who picked a custom driver get
there. Also disable custom drivers on Android 17 and its previews until
they've been tested there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 22:08:41 +01:00
Henrik RydgårdandClaude Opus 5.5 3c6876ac0e GPU: Don't estimate a first-frame safe size for screen-sized buffers
- Fixes #21802

The estimate from #21678 made the first-frame readback read back a part of
any buffer drawn in through mode. In the Japanese GTA games, that writes a
64x320 strip of the 32-bit loading screen into VRAM, where the two 16-bit
display buffers later go. Nothing else writes that memory, and when pausing,
the game shows one of them for a few frames before drawing it, which we then
display from memory, pink strip and all. Before, it was all black.

The estimate was for small render targets (Evangelion Jo's menu text), so
limit it to buffers smaller than the screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 21:22:21 +01:00
Henrik RydgårdandClaude Opus 5.5 a73b093fff Windows debugger: Don't edit a register on a double click on the category tabs
Releasing the button over the tabs also selected the top visible register,
so a double click there opened the change value dialog for it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 20:29:01 +01:00
Henrik RydgårdandClaude Opus 5.5 10af4afc72 Windows debugger: Make the left edge of the register category tabs clickable
The 16 pixel left margin of the register rows was excluded from every click,
including on the tab row, which has no margin, so most of "GPR" didn't
respond.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 20:24:47 +01:00
Henrik RydgårdandClaude Opus 5.5 d946f65270 ImDebugger: Fix the memory window stealing keys, and keys stuck after closing
The memory window's single-letter shortcuts (F, B, H, U...) were taken even
when it wasn't focused, opening the search form and focusing its text field
while the game had the keyboard. Only take them when the window is focused,
like the disassembly window does.

Key events don't reach imgui while the debugger is hidden, so a key held while
closing it stayed down. Clear imgui's key state while it's hidden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 19:08:34 +01:00
Henrik RydgårdandClaude Opus 5.5 8f6b43ce8e Fix the port offset hint: unmodified PSPs can't connect anyway
Offset 0 only helps with a real PSP running the old Pro Online plugin. Also
say that all players must use the same offset.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 18:56:58 +01:00
Henrik Rydgård bf11170ed4 Merge pull request #23015 from hrydgard/audio-clamp-audit
Audio: Fix wrapping overflows, filter the SAS reverb's rate conversions
2026-11-09 18:11:49 +01:00
Henrik RydgårdandClaude Opus 5.5 5972cd0f5a Update pspautotests for audio/reverb/upsample
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:34:54 +01:00
Henrik RydgårdandClaude Opus 5.5 4812d6fb04 Remove the unused AdjustVolumeBlock
Nothing calls it any more. Its SSE path also had the left and right
volumes swapped (_mm_set_epi16 takes its arguments high lane first).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:40 +01:00
Henrik RydgårdandClaude Opus 5.5 e3b9e54c23 sceSas: Add a hidden ReverbFilter setting
On by default. Off gives the hardware's unfiltered rate conversions
around the reverb: the send decimated by keeping the second frame of
each pair, and the output zero-stuffed at double level. With it off,
pspautotests' audio/reverb/upsample matches its .expected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:40 +01:00
Henrik RydgårdandClaude Opus 5.5 36fbf29364 sceSas: Filter the reverb send before halving its rate
The ME decimates the send by keeping one frame of each pair, so
everything above 11khz aliases into the reverb (pspautotests'
audio/reverb/upsample: a 22.05khz tone reaches it as DC). Use the
output side's half-band filter at half gain instead. Splitting the send
into its even and odd frames first makes each tap one multiply-add for
two outputs and both channels.

This deliberately departs from the hardware, like the output side.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:40 +01:00
Henrik RydgårdandClaude Opus 5.5 cf94ea8886 sceSas: Pass the send through at the full rate when no reverb is selected
The "off" path decimated the send to 22khz and then doubled every
sample, which folded everything above 11khz down. The ME runs a
separate full-rate loop for it instead: pspautotests'
audio/reverb/upsample shows a 22.05khz tone surviving with no reverb
selected. The comments on the reverb's resampling now cite that test
too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:39 +01:00
Henrik RydgårdandClaude Opus 5.5 621c2a7e21 sceSas: Run the reverb upsampling filter with CrossSIMD
Filter the whole grain at once, from a float history. Each input frame
gives one vector holding both output frames for both channels, already
in output order, so each tap is one load and one multiply-add.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:39 +01:00
Henrik RydgårdandClaude Opus 5.5 153d60c446 CrossSIMD: Add Vec4S32::StoreS16Sat
A signed saturating narrow to 16 bits. Vec4U16::FromVec4S32 can't stand
in for it: it saturates unsigned on SSE and LSX and truncates on NEON.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:39 +01:00
Henrik RydgårdandClaude Opus 5.5 463a85d8ab sceSas: Interpolate the reverb output instead of zero-stuffing it
The ME upsamples the 22khz wet signal by putting it on every other
44khz frame at double gain. That leaves a full-amplitude mirror image
of the reverb just below 22khz, which eats the mix's headroom: in
Outrun 2006 it put about a fifth of the output energy above 15khz and
made the final mix clip hard, mostly in the left channel.

Replace it with a 24-tap half-band interpolation filter (flat to 9khz,
-69dB from 13khz up), at the same average level. This deliberately
departs from the hardware.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:39 +01:00
Henrik RydgårdandClaude Opus 5.5 3c41ace5c8 Audio: Fix overflows that wrap instead of clamping, and swapped underrun padding
- StereoResampler: the interpolation multiplied a 17-bit difference by a
  16-bit fraction in 32 bits, which wraps when adjacent samples are more
  than half the range apart. Same with the volume multiply on a loud mix.
- StereoResampler: the padding after an underrun took left from the right
  sample and right from the left.
- SAS reverb: the four comb products could sum past 32 bits, and the
  return multiply overflowed once the output passed 16 bits.
- SAS: a fast decay can leave the envelope height negative for a sample,
  which mixed that sample inverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:29:39 +01:00
Henrik Rydgård aa7e5fa5dd Merge pull request #23014 from hrydgard/module-self-unload
Modules: Find the caller's module by address, fix self stop/unload
2026-11-09 17:28:18 +01:00
Henrik RydgårdandClaude Opus 5.5 89cb09ad79 Modules: Find the caller's module by address, fix self stop/unload
pspautotests modules/selfunload and modules/idlist show:

- sceKernelGetModuleId and the self stop/unload calls act on the module the caller's code is in,
  not the module that created the thread.
- Address lookups cover text_addr up to the text, data and bss sizes, and refuse kernel addresses
  from user mode (ILLEGAL_ADDR).
- sceKernelStopUnloadSelfModule takes (argSize, argp, status, option) and exits with 0. It was
  unimplemented for user mode and given the wrong arguments for kernel mode.
- When module_stop returns 0, the module is unloaded and the calling thread exits with its exit
  code. A return of 1 gives CAN_NOT_STOP; any other nonzero value gives NOT_REMOVABLE. In both
  cases the module stays started and the status gets the value.
- GetModuleIdList refuses a NULL or kernel count pointer.
- text_size leaves out .MIPS.abiflags.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 17:00:15 +01:00
Henrik Rydgård 893eb1cb27 Merge pull request #23012 from hrydgard/ge-pace-30fps
Add a "Limit framerate to 30 fps" setting, and a compat flag for it
2026-11-09 16:43:19 +01:00
Henrik Rydgård a7da7a6b7d Merge pull request #23011 from hrydgard/xmb-settings-persist
Keep more XMB settings, fix the Character Set error
2026-11-09 16:42:32 +01:00
Henrik RydgårdandClaude Opus 5.5 d50bb4d0dd Translate the 30 fps limit setting
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 13:35:50 +01:00
Henrik RydgårdandClaude Opus 5.5 8fbc3adfed Add a "Limit framerate to 30 fps" setting, and a compat flag for it
Many games drop to 30fps when they miss a vblank, and on the PSP some of them
nearly always do. In PPSSPP the GE is fast enough that they spend much of their
time at 60 instead, and some things misbehave (Midnight Club).

With the limit on, the GE takes until just after the vblank two on from the one
the previous frame was done in, so the frame goes up every other vblank whether
the game flips as soon as it's done, waits for a vblank first, or latches the
flip. A new frame starts at the first list after a flip, or at a list that
starts after a vblank, for games that enqueue their lists from the vblank
interrupt and never flip (Midnight Club: LA Remix).

Auto applies it to games with the LimitFrameRateTo30 compat flag, the two
Midnight Club games for now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 13:25:30 +01:00
Henrik Rydgård b1549195eb Merge pull request #23010 from hrydgard/libretro-d3d11-v2
libretro: Negotiate version 2 of the D3D11 render interface
2026-11-09 12:50:25 +01:00
Henrik RydgårdandClaude Opus 5.5 afa254133e Headless: Set the registry category version from the installed firmware
Headless has no config to keep the version the app stores on install, so
it stayed 1 and every XMB boot ran the registry upgrade, rewriting the
defaults of all keys added since 1.50, mapped settings included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 12:43:39 +01:00
Henrik RydgårdandClaude Opus 5.5 3c7beeaaee sceReg: Keep the UMD Video, slideshow, character set and password settings
- Fixes #22920

Map the XMB's /CONFIG/VIDEO keys (UMD menu, audio and subtitle language,
volume, L/R button, sequential playback, title display), the slideshow
speed, CHARACTER_SET/oem and ansi, and the lock password to new config
settings, so they survive a restart. The languages and password are BIN
keys, stored in the config as text ("en", "0000"); a setting of the wrong
length or with unprintable bytes isn't used. Defaults are the values of
our registry dump. Also fix two key names in the mapping comment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 12:43:39 +01:00
Henrik RydgårdandClaude Opus 5.5 45a5e3b722 sceIo: Accept the code page devctl on fatms0: too
devctl 0x02425856 sets the code page for 8.3 names (fatms.prx in 6.61
passes the word to sceCodepage). It was only handled on ms0:, and on
fatms0: fell through to the unimplemented path, whose
SCE_KERNEL_ERROR_UNSUP is the 80020325 the XMB showed after changing
System Settings > Character Set. Also check the argument like fatms does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 12:43:39 +01:00
Henrik Rydgård c6950d22ee Merge pull request #23007 from hrydgard/more-ui-fixes
More UI fixes
2026-11-09 11:59:40 +01:00
Henrik RydgårdandClaude Opus 5.5 c1128ce35a libretro: Negotiate version 2 of the D3D11 render interface
Under version 1, a frontend that presents from another thread (RetroArch's
threaded video, now its default) can only hand the core a deferred context,
which can't map a staging texture or read anything back. Texture uploads that
go through a staging texture failed there ("Failed to create DrawPixels
texture"), and so would every readback.

Version 2 shares the immediate context by taking turns. We hold it for the
whole of retro_run and around savestates, reset and unload, wait for the
frame's sync index before taking it, copy the frame into a texture per sync
index and hand that over with set_texture, and let go of it before
video_refresh. A frontend without the negotiation hands out version 1, which
works as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 11:39:27 +01:00
Henrik RydgårdandClaude Opus 5.5 b185d746ee D3D11: Unbind the GS/HS/DS stages at the start of each frame
- Fixes #22748

thin3d never uses these stages, so it never set them. A libretro frontend
shares the immediate context with us, and recent RetroArch leaves its sprite
geometry shader bound after drawing its frame, so every one of our draws went
through it and the core output was black (with threaded video off, where the
core draws on the frontend's context).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 11:28:25 +01:00
Henrik Rydgård c3ab986b74 Merge pull request #23006 from hrydgard/remove-gl-skip-mode
OpenGL: Remove skip mode
2026-11-09 11:13:44 +01:00
Henrik Rydgård 1ef159f3e4 Prettify some popups. 2026-11-09 11:06:53 +01:00
Henrik RydgårdandClaude Opus 5.5 8587463502 UI: Keep the pause screen out of a hidden navigation bar's area
With the navigation bar hidden, a swipe from the edge brings it back for
a while, over the pause screen's buttons on that edge. Android now also
reports where the navigation bar is when it's hidden, and a screen can
reserve that area with ReserveHiddenNavBar(). The pause screen does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 11:02:56 +01:00
Henrik RydgårdandClaude Opus 5.5 5d9ff611f6 OpenGL: Remove skip mode
Since the native EGL path, the Android context stays current on the
render thread until the render manager and the draw context are gone, and
it's destroyed with every surface. So the GL calls skip mode avoided
after the emu thread exits (Android was the only platform that set it)
can just run, and nothing it would have leaked outlives the context.

It was also a trap: a shader created while it was on was never compiled,
but not marked failed either, so a program linked from it later failed
with "missing shader". Reports of that stopped with 3cb6ada66a, which
already took most of its uses away.

ThreadEnd still frees the steps that never got submitted without running
them, now called a dry run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:41:02 +01:00
Henrik Rydgård a7d80b680a Merge pull request #23003 from Narugakuruga/patch-40
Update Chinese translations, add translation document in English
2026-11-09 10:38:23 +01:00
Henrik Rydgård 33de146e23 Merge pull request #23005 from hrydgard/android-fixed-surface-rotation
Android: Re-fix a hardware scaled surface when the view is resized
2026-11-09 10:36:42 +01:00
Henrik RydgårdandClaude Opus 5.5 366e0c795c Android: Re-fix a hardware scaled surface when the view is resized
With a display resolution set (iAndroidHwScale), the surface has a fixed
size, and a rotation doesn't change it, so no surfaceChanged came to
re-fix it there. Landscape kept rendering into the portrait-sized buffer.
A layout listener on the SurfaceView now re-measures and re-fixes it,
which brings a surfaceChanged with the new size.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-09 10:10:55 +01:00
Henrik Rydgård 79e845c4d0 Merge pull request #23004 from hrydgard/color-test-screen
UI: Add a color test screen to Developer tools > Tests
2026-11-09 09:47:53 +01:00