Commit Graph
724 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 d0e3141f43 FFmpeg: Vendor what PPSSPP uses into ext/ffmpeg, drop the submodule
The ffmpeg submodule held prebuilt libraries for every platform next to the
sources (about 1.5 GB checked out), and nothing uses those any more. Only the
needed sources are copied in, from the submodule's commit, along with every
header and template they include. The path is new, so checking out commits on
either side of this works.

It's also cut down to what PPSSPP uses: the H.264, AAC, MP3, ATRAC3 and ATRAC3+
decoders, the H.264 parser, the demuxers as before, and the FFV1 encoder, AVI
muxer and file protocol for AVI dumping. config.h takes its CONFIG_ values from
FFmpeg 3.0.2's own configure run with just those enabled. The raw H.264 demuxer
stays even though nothing opens raw H.264: probing PSMF data uses it to identify
the video stream's codec, which otherwise comes out as none.

On top of that:
- The files nothing links (configure would build them, but they're never pulled
  out of the static library, going by the GCC link map) are left out: mostly
  libavutil's crypto and hashing and the alternative DCT/IDCT/FFT versions.
- libswresample isn't built, now that nothing uses it.
- The H.264 decoder only does 8-bit video, which is all the PSP has. The SPS
  parser rejects any other bit depth, and the DSP files no longer build their 9-
  to 16-bit variants, which the linker kept because the init functions pick one
  by bit depth at run time.

That's 160 files to compile instead of 277, and 391 of FFmpeg's vendored, about
5.8 MB. The README in ext/ffmpeg has what was done, the PPSSPP patches in the
copy, how to add a component, and the tradeoffs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 22:27:54 +01:00
Henrik RydgårdandClaude Opus 5.5 03ac2c8ded libretro: Link FFmpeg as a static library of its own
With its objects on it, the MSVC link command line got too long for Windows.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 22:27:53 +01:00
Henrik RydgårdandClaude Opus 5.5 70a0a9dd00 Android, libretro: Build FFmpeg from source
The ndk-build builds (android/jni and libretro/jni) get a static library module
with the files in ext/ffmpeg-build/sources.mk, in place of the prebuilt
libraries. The libretro Makefile compiles them itself, with FFmpeg's include
directories first so its config.h wins over the others on the include path, and
puts the objects in obj-ffmpeg/ rather than next to the sources, where a
configure build may have left its own.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-25 22:27:53 +01:00
Craig Carnell 28ac694bf6 Add libretro VR support 2026-10-24 17:32:15 +01:00
Craig Carnell 64e4581863 Update libretro-common 2026-10-24 12:33:48 +01:00
Henrik RydgårdandClaude Opus 5.5 23dffa9db3 POPS: Boot PS1 disc images as converted EBOOTs made on the fly
A cue sheet, a CloneCD .ccd, or a bare .bin, .img or .iso of a PS1 disc
now boots on the firmware's POPS, as the converted EBOOT.PBP popstation
would make from it. PS1EbootFileLoader builds the PBP header, PARAM.SFO
(the disc ID from SYSTEM.CNF) and the PSISOIMG header, TOC and block
index, and serves the disc image from the image's own files. Each block
of 16 sectors is a stored DEFLATE block: the manager won't read an image
of uncompressed blocks in its own format, but the converted PBP's inflate
takes stored ones, and with every block the same size, reads map straight
onto the files. Nothing is compressed or written anywhere.

Cue sheets can have any number of files, AUDIO tracks, INDEX 00 and
PREGAP, and a missing FILE falls back to the cue sheet's own name. A
2048-byte .iso gets Mode 2 Form 1 sectors made around its user data.

The EBOOT is mounted as the only file in host0:, through BlobFileSystem,
which now saves its open handles in savestates. The game browser lists
.cue, .ccd, .bin and .img, leaving out the .bin and .img files a cue
sheet or .ccd next to them describes, and a bare image opened directly
goes through the cue sheet that names it. GameInfoCache reads the title
and ID of these, and of real PS1 EBOOTs, from their PARAM.SFO.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 15:01:22 +02:00
Henrik RydgårdandClaude Opus 5.5 fcfac13643 Share the drop shadow code between the UI atlas and the text drawer
CompositeDropShadow in Common/Render/DropShadow.cpp blurs a premultiplied
RGBA image's alpha (with an optional offset) and composites the image
over it. The atlas's AddDropShadow and TextDrawer::AddDropShadow are now
thin wrappers that pick the parameters.

The blur scatters only the non-transparent texels, which makes atlas
shadows 3-7x faster than the old gather-with-clamping version. Atlas
output is unchanged apart from rounding (alpha differs by at most 1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 11:56:24 +02:00
Henrik RydgårdandClaude Opus 5.5 56c76ace35 thin3d: Swapchain objects, and multiple swapchains on Metal
The backbuffer is now a Swapchain, from GetPrimarySwapchain(), and
callers bind, measure and read it back through that instead of nullptr.
nullptr still means it too. Backends with one swapchain map the primary
to their old backbuffer path.

On Metal, CreateSwapchain() adds more, each with its own layer, depth
buffer and drawable. Passes merge per swapchain, and Present() presents
every drawable acquired that frame. The backbuffer is just the first
of them. Nothing creates a second one yet.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 18:42:53 +02:00
LunaMooandClaude Opus 5.5 3ce3973781 Add overlay (bezel) support
Draws a user image around or behind the PSP screen, to fill the black bars
on displays whose aspect ratio doesn't match the PSP's (#20325).

- Overlays are PNGs in PSP/OVERLAYS. A plain PNG there just works: it's
  drawn in front of the game, and its transparent hole is found by walking
  from the image center to each edge until a nearly opaque pixel. Existing
  RetroArch overlay images can be dropped in as-is.
- A subfolder with an overlay.ini can define overlays with a Name, Layer
  (Foreground/Background) and an explicit Hole=x,y,w,h.
- "Load overlay image..." in the display layout screen imports any PNG
  (including Android content URIs) into the overlays folder and selects it.
- The overlay is fit to the screen (aspect preserved, centered). The hole is
  mapped with the same scale, and the game is fit into it with the normal
  stretch / integer scale / aspect ratio options. Offset and scale don't
  apply while an overlay with a hole is active. This goes through
  CalculateDisplayOutputRect, so touch mapping and post shaders agree.
- The selection is a per-orientation, per-game DisplayLayout setting.
- Disabled in VR, Cardboard, and with skip buffer effects (except software
  rendering), since the presentation path doesn't run there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QGBg32EFPsTXjAFu7dnTcz
2026-10-22 14:09:51 +02:00
Henrik Rydgård 1adf3c553d Merge pull request #22549 from Kethen/aemu_postoffice_enet
UDP(ENet) mode for adhocctl & aemu_postoffice relay
2026-10-21 23:51:28 +02:00
Katharine Chui 880158cfdb initial enet mode for adhocctl & aemu_postoffice relay 2026-10-21 14:19:54 +02:00
Henrik RydgårdandClaude Opus 5.5 0b1e1a9bb3 POPS: Boot PS1 EBOOTs through the firmware's POPS manager
A PS1 EBOOT now boots the installed firmware's POPS manager
(flash0:/kd/popsman.prx), which loads its PS1 emulator (pops_0Xg.prx) for
the game. Load_PSP_POPS stands in for the kernel's reboot into its POPS
configuration: it loads the manager and that configuration's user modules,
and a helper thread makes the kernel init's scePopsManLoadModule(path, 0)
call. InitForKernel reports a POPS boot from the memory stick.

The emulator plays its sound on the Media Engine, so a PS1 boot always
gets the emulated ME, whatever the homebrew setting says, and is refused
on platforms that can't emulate it. The manager boots the ME with its own
code (POPS's reboot has no me_wrapper, so Sony's ME firmware isn't booted
for it), and its ME loop runs there unchanged, playing through the audio
block.

Everything in POPS that reaches hardware registers is kernel code, so a
POPS boot leaves the ME's kernel mode stopgap (g_kernelModeAnywhere) off:
7% fewer host instructions in Crash Bandicoot.

The manager also drives the GE directly: its stall register and FINISH
status are an MMIO device that only answers during a POPS boot, and stall
writes extend the HLE GPU's current list.

The 6.60 and 6.61 popsman.prx and pops_01g/02g.prx have the same code. The
manager's is checked when it's loaded, and any other one fails the boot
with a message. Savestates include the boot's threads.

Reading a game's disc image needs the next two changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 13:15:30 +02:00
Francisco José García García 539490b0c8 HLE: sceAmctrl_driver, on libkirk's amctrl
amctrl.prx's PGD (BB) MAC and cipher functions, for kernel modules that
import them: the firmware's POPS manager checks and decrypts a store PS1
game's disc image with them. libkirk's amctrl.c reimplements the module, and
its MAC_KEY and CIPHER_KEY have the layout of the contexts the callers keep in
their own memory, so those are used in place. 6.60 NIDs.
2026-10-21 12:50:45 +02:00
Henrik RydgårdandClaude Opus 5.5 8af7643efa ME: sceSysreg_driver's ME reset and clock calls, MMIO copies in sysclib
The calls homebrew starts the ME with (1.50's NIDs, and 3.71's for the
ME's reset and bus clock) set or clear a bit of the reset or bus clock
register the way the firmware's driver does, returning whether it was
set. Only those NIDs, so a later firmware's lowio.prx keeps its own
exports under --vsh.

Kernel modules copy their ME code to the boot page with SysclibForKernel's
memcpy, which now goes through MMIO for hardware addresses like the
replaced memcpy already did (MMIO::Copy, shared).

pspsdk's mebasic, MElib's test, PSP Bunny, snes9xTYL and ProTrekkr's test
now start their ME.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 12:06:11 +02:00
Henrik RydgårdandClaude Opus 5.5 e52cc38866 ME: Reset, interrupts and the other registers homebrew runs the ME with
Sysreg (0xBC100000) gets the ME's reset bit (0x4C bit 2), the soft
interrupt (0x44, which interrupts the other CPU: the ME's controller from
the main CPU, PSP_MECODEC_INTR from the ME), the hardware mutex (0x48,
each CPU sets its own bit only while the other's is clear) and the clock
and config registers it writes. The ME's interrupt controller (0xBC300000,
write-1-to-clear, mask at 8) answers the ME only. All of it is the ME's
state and stays unhandled without an ME.

On the ME: interrupts to EBase with EPC and EXL, halt sleeping until an
unmasked interrupt, and Count, which doesn't run: it stays 0 across 10ms
with ERL set after reset and with Status cleared, and reads back what was
written. Reset keeps the GPRs and sets Status ERL/BEV/SR, which homebrew
relies on: mcidclan's samples run C on the stack Sony's ME code left. The
values are from a kernel probe on a PSP-1000 (sp 0x801FFFE0, COP0 22 = 1,
Status 0x20500404, mfic 0, which doesn't gate interrupts).

The main CPU runs base interrupt handlers the way interruptman calls them
(a0 intno, a1 arg, a2 interrupted pc; -2 disables), and interrupt 31 has
a stand-in for me_wrapper's handler, which homebrew releases first.

While the ME is emulated, any main CPU code may access hardware registers:
homebrew calls its own code in kernel mode through a kcall module. This
is a stopgap (g_kernelModeAnywhere, marked HACK): kernel mode should be
part of the CPU's state, switched on while a kernel module's export runs.
The memcpy/memmove replacements copy through MMIO when an end is a
register address, for code copied to the boot page.

mcidclan's me-soft-interrupt sample now runs, counting each interrupt in
both directions.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 09:33:26 +02:00
Henrik RydgårdandClaude Opus 5.5 fef84cf0ca CPU: Add the Media Engine core, off by default
MeCore owns a second MIPSState in the ME's address space, held in reset
until released (SetReset). It runs on the interpreter, a slice behind the
main CPU: CoreTiming runs it for the cycles the main CPU has just used, in
Advance and ForceCheck. Its own PRId (COP0 22) and mfic/mtic flag; MMIO
counts as kernel mode on it, and a syscall stops it with an error rather
than reaching HLE. The interpreter's block stepping reads delay slots
through the stepping CPU's memory, and cache instructions log at verbose
level, as ME code flushes its caches in a loop.

Created at boot only for homebrew (PBP with MG category or no SFO, ELF;
the VSH counts, as vshmain.prx loads as an ELF), when "Enable ME
emulation for homebrew" is on: a global checkbox in developer settings,
off by default and not translated yet, or --me-core. Saved in its own
section after MMIO (SaveStart v5), with its own memory; loading a state
creates or removes the ME to match.

The boot page now starts with a reset stub that sends the ME on to
0xBFC00040, where homebrew puts its code (from the firmware's reset code,
read on a PSP-1000).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 22:22:40 +02:00
Henrik RydgårdandClaude Opus 5.5 b7b4a265b7 MMIO: Register hardware register blocks as devices
The interpreter's MMIO dispatch was a hardcoded chain for GPIO and the syscon
serial port. Devices now register an address range in Core/HW/MMIO and get
each access with its width and the MIPSState making it, for registers that
answer each CPU differently. An access no device handles is logged and reads
as poison, as before.

GPIO and syscon serial become the first two devices. They're reset at boot,
which they never were, and saved in savestates (SaveStart section version 4).

ll/sc, lwl/lwr and lwc1/swc1 reach MMIO in the interpreter too, and kernel
blocks leave lwc1/swc1 to it like the other loads and stores. swl/swr and
lv/sv still treat it as a bad address. TestMMIO runs a kernel-mode access on
each core and the registers through a savestate.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:36:52 +02:00
Henrik RydgårdandClaude Opus 5.5 7202904f60 libretro: Include SaveState.h for SaveStart, now declared there
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 21:32:43 +02:00
Henrik RydgårdandClaude Opus 5.5 a62aa69986 libretro: Use the real SaveStart
libretro declared its own, which no longer matched once SaveStart got a
member, so serializing read an uninitialized byte. It's in SaveState.h
now.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 20:18:46 +02:00
Henrik Rydgård 6015ff06a7 Merge pull request #22616 from LunaMoo/native-cso-pack
Add built-in CSO packing functionality
2026-10-19 18:53:00 +02:00
Claude 363d816789 Game screen: Compress game as CSO
"Compress game" in the game screen's ... menu, for ISO, CSO, CHD and PSN
EBOOT.PBP games. It opens a list of the CSO presets (and Extract to ISO
for anything that's not an ISO already):

- Best: libdeflate level 12, 64K blocks
- PSP Compatible: zlib level 9, 2K blocks, readable by custom firmware

These match maxcso's presets, and the CSOs come out byte-identical to its.
The writer, Core/FileSystems/CSOCompress, reads the input through PPSSPP's
own block devices, so recompressing is a single pass with no temporary
file.

The original is deleted when done, unless "Keep the original file" is
checked (off by default). When the new name is taken, by a kept original
or another file, a number is added to it.

The work runs on a thread using every core, with a progress bar and time
left at the bottom of the game screen. It keeps going when the screen is
left, and the ... menu offers Cancel meanwhile. On the game list the
game's icon is covered by "Compressing...", and clicking it opens the
game screen instead of playing. When done, recents follow the new file
and the game screen and lists refresh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCxekYqPnzNr5d8Tp1q7aZ
2026-10-19 16:01:53 +02:00
Claude 4ab1066ade ext: Add libdeflate's deflate encoder
Only the compressor (deflate_compress.c, utils.c and their headers) from
libdeflate 1.7, the version LunaMoo/maxcso vendors, for writing CSO files.
Built as part of Core on every platform. MIT license.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CCxekYqPnzNr5d8Tp1q7aZ
2026-10-19 15:58:54 +02:00
Henrik RydgårdandClaude Opus 5.5 d90ee09144 libretro: Add the permission stubs
The ad hoc code now asks for the local network permission, so Core needs them.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 22:11:39 +02:00
Henrik Rydgård 49eea8645e Merge pull request #22605 from hrydgard/darkstalkers-libretro-native
libretro: Hand DarkStalkers' 384x224 source image to the frontend
2026-10-16 14:14:55 +02:00
Henrik RydgårdandClaude Opus 5.5 39205d99ad libretro: Hand DarkStalkers' 384x224 source image to the frontend
- Fixes #21739

With the DarkStalkers hack, SoftGPU skips the game's stretch blit and
stretches the source image to the screen itself. Libretro always presents
software rendering at 480x272, so that stretch happened at 1x and the
frontend then scaled up a blurry image.

Now libretro gets the 384x224 source as is, with the aspect the game would
have stretched it to, and switches back to the full frame when the game
stops using the stretch. GL and D3D11 read the frame from a corner of their
larger framebuffer. RetroArch's Vulkan driver samples the whole image the
core hands it, so the Vulkan presentation images are resized to the frame.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 13:57:16 +02:00
Henrik Rydgård 0a9b57371f Delete the spline quality setting 2026-10-16 13:27:26 +02:00
Henrik Rydgård f5255eefaf Move the Hardware Transform setting to developer tools, reset by renaming the key.
This setting should always be on, not having it ruins performance.
2026-10-16 13:27:23 +02:00
Henrik RydgårdandClaude Opus 5.5 1d7487e5a7 GPU: Add a null GPU, and headless --graphics=null to use it
GPU_Null derives straight from GPUCommon and has no thin3d context, framebuffer
manager, texture cache or shaders. It runs display lists with the flow control,
bounding boxes, matrix loads (the hardware backends'), immediate vertices and
block transfers of the others, moves the vertex and index pointers past each
draw and curve, and charges the per-vertex and fill cost the software renderer
does. A DrawEngineCommon that queues nothing provides the vertex decoders.

It's for measuring the CPU emulation. From savestates, God of War, Tekken 6,
Wipeout Pure and LocoRoco flip the same frames in 10 emulated seconds as with
Vulkan and software, in 44-77% fewer instructions than Vulkan.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-16 01:12:38 +02:00
Henrik RydgårdandClaude Opus 5.5 1d5e2689b5 JIT: Add --jit-profile, a sampling profiler for the CPU cores
The native IR JITs get the emulator thread's host PC sampled every 50 us (a
signal on macOS and Linux, SuspendThread on Windows), mapped to blocks, the
routines they call and host functions. The report has each hot block's MIPS,
IR and host code with the samples per host instruction. The IR interpreter's
block timing, previously behind IR_PROFILING, now runs on the same switch.
Both cost nothing when off.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 11:01:52 +02:00
Henrik RydgårdandClaude Opus 5.5 f3c69fc5d1 Remove FakeJit and the pre-IR JitBlockCache
FakeJit was the native JIT for architectures without one, but the config
already forces those onto the IR interpreter, so CreateNativeJit() now
returns that instead. The vertex decoder fallback no longer needs
FakeEmitter.

JitBlockCache was the block cache of the pre-IR JITs. Its header keeps
the debug interface types the IR block caches use. Also removes the
JitInterface link hooks only it called, and the JitState fields tied to
it. This fixes a null dereference in the ImDebugger memory section,
which read GetBlockCache(), always null with the IR JITs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-15 02:24:25 +02:00
Henrik RydgårdandClaude Opus 5.5 74703b031e Remove the legacy ARM32 JIT
The IR-based one replaces it. With that, every native JIT is IR-based, which the JIT viewer and
the settings' comments now assume. The ARM emitter test loses its part that drove the old FPU
register cache.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:32:53 +02:00
Henrik RydgårdandClaude Opus 5.5 6d105ae35d ARM32: Start an IR-based JIT
The backend follows the ARM64 one: a dispatcher, a register cache on top of the IR one, and
native exits, syscalls, breakpoints and transfers. Everything else goes to the IR interpreter
for now. Floats are mapped one lane per S register (no SIMD mapping yet), and addresses are
masked, as on every 32-bit build.

The JIT core now uses it on ARM32 in place of the old ArmJit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 17:32:53 +02:00
Henrik RydgårdandClaude Opus 5.5 66d7975e7f Remove the legacy (non-IR) x86-64 and ARM64 JITs
Their IR-based replacements stay. The JIT core now creates the IR JIT on both, so "JIT using
IR" is the same as "JIT" on every architecture (ARM32 still uses its legacy JIT for both). The
settings no longer offer it, a saved JIT_IR loads as JIT, and the JIT harness and CPUEquivalence
fuzzer drop the duplicate run.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-14 14:39:45 +02:00
715c13dcba libretro: let a pending boot finish before unload and reset
retro_unload_game() and retro_reset() could call PSP_Shutdown() while the
loader thread was still booting, tearing down memory and file systems
under it, or after it had failed and already shut down, which asserts.
They now drain PSP_InitUpdate() first, and drop a state queued for the
boot.

Based on 2ac075c3dd from libretro-fork/psp, kept to the libretro side.

Co-Authored-By: Codex <codex@openai.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 13:52:43 +02:00
CodexandClaude Opus 5.5 112fad2e07 libretro: update the buttons in one call
retro_input() set or cleared each button with its own
__CtrlUpdateButtons() call, so with the GL emu thread running the game
could sample a mix of the old and new button state.

(The input part of 1bb8e3797e from libretro-fork/psp.)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 13:51:10 +02:00
Henrik RydgårdandClaude Opus 5.5 299cbcfe68 libretro: check the state size inside MeasureAndSavePtr
The size check in retro_serialize measured the state separately before
MeasureAndSavePtr measured it again, a third DoState pass on every save,
which rewind and run-ahead do every frame. MeasureAndSavePtr now takes
the capacity of a caller-provided buffer and fails after its own measure
pass if the state doesn't fit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 13:50:54 +02:00
libretroadminandClaude Opus 5.5 fb61ec51cb libretro: create the GL presets once
LibretroHWRenderContext::ContextReset() already creates them right after
CreateDrawContext(), so the GL contexts' own call leaked the first set.

(The libretro part of 329f30a0c9 from libretro-fork/psp.)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 13:50:33 +02:00
libretroadmin b71fbaeb5c libretro: fix OOB, UAF, data races and control flow in core glue
System_AudioPushSamples converts straight into the output buffer: the
block loop never advanced the source pointer and copied numSamples*2
int16s out of a 2048-sample stack buffer, a stack OOB read for any push
over 1024 frames. Realloc failure drops samples instead of crashing and
log_cb is NULL-checked. retro_serialize refuses to write a state larger
than the frontend's buffer, retro_get_memory_data/size return nothing
until PSP memory is mapped, deferred unserialize no longer leaks the
previous buffer, and the cheat entry points stop leaking a CWCheatEngine
per call.

The emu thread acknowledges a pause with a CAS so it cannot clobber a
concurrent quit request. EmuThreadStop stops and joins from any live
state, so unloading while paused no longer leaves a thread running over
freed state. EmuThreadPause pumps queued frames until the thread parks,
via a new non-blocking GLRenderManager::HasQueuedThreadWork() check,
instead of draining one frame, which deadlocked when the thread was
blocked on a readback sync in the next frame. retro_run resumes a paused
thread and pauses it before check_variables() rewrites g_Config,
retro_reset stops it before PSP_Shutdown(), and the sleep_ms(4) after
resume is gone.
2026-10-13 13:50:05 +02:00
libretroadmin 8abc5920c6 libretro: include <array> for the cheat file buffer
MSVC doesn't get std::array through the other headers, so libretro.cpp failed to build there.
2026-10-13 13:49:41 +02:00
Henrik RydgårdandClaude Opus 5.5 6cf4872e78 Android: Hand microphone input over on the CPU thread, like the other hosts
The Oboe input callback used to call Microphone::addAudioData directly,
writing PSP memory from the audio thread. Now it only pushes samples
into a SampleRing, and pollRecording drains it on the CPU thread.
Starting and stopping still go through Java, which asks for permission.

Every host with a microphone polls now, so sceUsbMic drops what only the
push path needed: QueueBuf's recursive mutex, restarting the mic on a
device change, and the startMic parameter nobody read. Also removes the
unused System_AudioRecordingState and Microphone::isNeedInput.

The Java microphone_command branch didn't return true, so every command
logged "processCommand failed".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 18:49:21 +02:00
Henrik RydgårdandClaude Opus 5.5 a89fdb2c9a SoftGPU: Remove the pixel and sampler JITs
The C++ paths draw and sample four pixels at a time in vector lanes,
while a JIT function only does one, and with a JIT function in use the
span and quad paths were skipped. On x86 the JITs had become slower:
Wipeout took 13% more wall time and 25% more CPU with them, God of War
3% more. They were also a second implementation of every GE rule, and
ARM never had them.

The SoftwareRendererJit setting goes with them. RasterizerRegCache.h
keeps only the types the pixel and sampler functions take, as
RasterizerTypes.h.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-10 13:44:48 +02:00
Henrik RydgårdandClaude Opus 5.5 32c41a3417 SoftGPU: Gather the GE arithmetic in GEMath.h
The float24 truncations, reciprocal and rsqrt tables, GE adder and row sums,
the setup reciprocal for planes, the mip log2, texture coordinate precision,
the lighting pow and color scaling, and the antialiased line alpha, from
TransformUnit, Rasterizer and Lighting, so they can be unit tested. No
behavior change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-02 15:09:43 -06:00
Henrik Rydgård 49f92ebcb6 Merge pull request #22368 from hrydgard/remove-minimp3
Remove minimp3
2026-09-28 11:31:40 -06:00
Henrik RydgårdandClaude Opus 5.5 761e2f3706 Remove minimp3
MP3 emulation already went through FFmpeg, leaving MiniMp3Audio dead.
The one live user was loading MP3 UI sound effects (custom achievement
sounds), which now splits the file into frames and decodes them with
the FFmpeg MP3 decoder.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 10:57:02 -06:00
Henrik RydgårdandClaude Opus 5.5 5f261bd7ff Utility: Stand in for the HtmlViewer, offering to open the page in a browser
Instead of the PSP's web browser, a dialog shows the URL the game wants
and opens it in the host's browser on X, or backs out on O. Either way the
game sees the browser closed normally. Platforms that can't open a URL
(the new SYSPROP_CAN_LAUNCH_URL) only offer to back out. Only plain
printable-ASCII http(s) addresses are handed over, and on Linux without a
shell.

What the firmware does (sceUtility_Driver, 6.61, plus
utility/dialog/htmlviewer): the HtmlViewer has its own state apart from the
other dialogs, so they don't block each other, and its calls return
WRONG_TYPE until one has started. The request size picks the 2.00 to 3.00
layout, and InitStart allocates 3.5MB of user memory (4.5MB with options
bit 0x400 from 2.70 on), failing with 800200d9 without it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-25 12:50:23 -06:00
Henrik RydgårdandClaude Opus 5.5 e932d55f1c Build: Only turn off floating-point contraction for CPU emulation
The vertex decoder's C++ steps may fuse, like the vertex JITs do; with
contraction off everywhere, RISC-V's VertexJit test found the JIT and
the steps disagreeing on morphed float UVs. The flag now applies to
Core/MIPS only, in CMake and the libretro Makefile. ndk-build has no
per-file flags, so the legacy Android.mk goes back to the default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:59:04 -06:00
Henrik RydgårdandClaude Opus 5.5 1206528e45 Build: Turn off floating-point contraction for C++
Clang and GCC fuse a * b + c into one rounding on CPUs that have fused
multiply-add, which on ARM64 made the interpreter's dot products, vavg,
vdet and vqmul round differently from x86-64. Fused operations now only
happen where the code asks for them. MSVC doesn't contract by default.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 12:24:43 -06:00
Henrik Rydgård 428c1a6aa6 Merge pull request #22343 from hrydgard/vfpu-interpolator
VFPU: Replace fp64's correction tables with accurate implementation of special functions
2026-09-24 10:46:33 -06:00
Henrik RydgårdandClaude Opus 5.5 d6b3d590eb VFPU: Compute log2, sin/cos and asin without correction tables, too
They use the same quadratic interpolator as rcp and friends, with three
twists. sin indexes the quarter wave from the top, and asin and sin work
in a per-segment exponent whose 4-ulp truncation also applies to results
in a lower binade. log2 truncates exponent + log2(1.m) toward zero to 22
significant bits, and where that step is coarser than 2^-24 the datapath
drops coefficient bits to match; that also covers the region just below
1.0 that needed a special case.

vfpu_sincos now reduces the angle once. With every table gone, so are
the asset folder, the loader, InitVFPU and the fallbacks for tables that
failed to load. All seven functions are bit-exact with the table-based
code over every 32-bit input.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-24 10:07:01 -06:00
Henrik RydgårdandClaude Opus 5.5 55e9862b90 libretro: Build PSPPlaceholderDialog
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 19:30:31 -06:00