Commit Graph
48067 Commits
Author SHA1 Message Date
Henrik Rydgård a9d63d2ee1 Merge pull request #22354 from hrydgard/tlspl-allocate
Implement _sceKernelAllocateTlspl
2026-09-25 10:36:46 -06:00
Henrik RydgårdandClaude Opus 5.5 f47269864a _sceKernelAllocateTlspl: Check user pointers, support the timeout
The third argument is a timeout pointer, as threadman.prx shows. A kernel
address from user mode is ILLEGAL_ADDR there; we used to write through it.
Also, no lookup by index: the syscall requires the exact uid.

Adds the threads/tls/allocate test, recorded on hardware.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 10:05:07 -06:00
Henrik RydgårdandClaude Opus 5.5 ac39c55c36 Implement _sceKernelAllocateTlspl
This is the syscall usersystemlib's sceKernelGetTlsAddr makes when the
thread's cached TLS address is null, as (uid, &addr, 0). Code that has to
run before usersystemlib.prx is loaded (like plugins built with a Rust SDK)
inlines sceKernelGetTlsAddr and imports this directly.

Shares the allocation with sceKernelGetTlsAddr. A thread waiting on a full
pool stores its address pointer as the wait value, so no state changes.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 10:04:44 -06:00
Henrik RydgårdandClaude Opus 5.5 2b954b6a37 docs: Replace the headless hang history with what each GPU backend does
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:47:58 -06:00
Henrik RydgårdandClaude Opus 5.5 31dc2d47b5 docs: Headless OpenGL no longer hangs, and runs offscreen on macOS
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:47:58 -06:00
Henrik RydgårdandClaude Opus 5.5 ea101b714f Headless: Run OpenGL offscreen on macOS, without a window
A CGL context with no drawable, rendering into a framebuffer object of its
own that stands in for the backbuffer through g_defaultFBO. Core profile,
as the SDL app uses on macOS.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:47:58 -06:00
Henrik RydgårdandClaude Opus 5.5 c9cddb99e9 Headless: Present OpenGL frames too
OpenGL's render thread only finishes a frame when it's presented, so the
emu thread eventually waited forever in BeginFrame for a free frame, with
the render thread waiting for work. GPU tests and games hung, silently,
as a blocked host thread also defeats the timeouts.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:47:58 -06:00
Henrik Rydgård 47730e0eb0 Merge pull request #22353 from hrydgard/headless-vulkan-mac
Get Vulkan working on PPSSPPHeadless for Mac
2026-09-25 09:44:52 -06:00
Henrik Rydgård 48797bfe26 Merge pull request #22352 from hrydgard/ir-pass-fixes
Claude code review for IR optimization passes: Bug fixes and improvements
2026-09-25 09:26:22 -06:00
Henrik RydgårdandClaude Opus 5.5 bc8f0f29c4 docs: Headless Vulkan runs offscreen, and is the one to use for games
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:07:23 -06:00
Henrik RydgårdandClaude Opus 5.5 cc83084c94 Headless: Run Vulkan offscreen, without a window
Vulkan no longer needs a hidden window (which on macOS could never work, as
the Metal window description has no data2). It now uses the offscreen mode,
and presents each frame like the app does, as an unpresented frame would
wait forever for its next image. MoltenVK's console logging is limited to
errors, as it mixed into the test output.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:06:56 -06:00
Henrik RydgårdandClaude Opus 5.5 1a3addf0cb Mac: Look for MoltenVK outside the app bundle too
Executables outside a bundle (headless) found no Vulkan library. Also try
the app bundle built next to them, the Vulkan SDK's install and Homebrew's.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:06:56 -06:00
Henrik RydgårdandClaude Opus 5.5 23ba2f62f8 Vulkan: Don't wait for an image in frames that never acquired one
A frame that never draws to the backbuffer never acquires an image, but
its final submit still waited on the acquire semaphore, which nothing
signals, hanging the GPU. Skip the swap for such frames when finishing
them. This replaces the check for a frame with no steps at all, which
could also set it partway through a frame that acquires later.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:06:56 -06:00
Henrik RydgårdandClaude Opus 5.5 0b778d6b83 Vulkan: Add an offscreen mode to VulkanGraphicsContext
For when there's nothing to present to. Instead of a surface and swapchain,
it renders into images of its own through the VulkanPresentation interface
libretro uses, picking the graphics queue without a surface. Acquiring and
presenting signal and wait on the frame's semaphores with empty submits.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 09:06:56 -06:00
Henrik Rydgård a50fb6071f Merge pull request #22351 from hrydgard/jit-call-optimizations
JIT function-call optimizations
2026-09-24 16:59:39 -06:00
Henrik RydgårdandClaude Opus 5.5 dab5d82227 IR: Forward stores and loads to later loads in the block
OptimizeLoadsAfterStores only dropped a load right after a store of the same
reg. Now a load of anything the block stored or loaded before becomes a reg
move (with the extension for 8/16-bit loads), as long as nothing in between
may have changed the memory, the address reg, or the reg holding the value.
Only a store through the same base at a disjoint range is known not to alias,
and constant addresses outside RAM are left alone.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:56:03 -06:00
Henrik RydgårdandClaude Opus 5.5 1cdc432d6a IR: Let vrot's FSinCos write straight into an [s, c] pair
When the cosine lane follows the sine lane, FSinCos can write both in place
instead of going through a temp and two FMovs.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:42:03 -06:00
Henrik RydgårdandClaude Opus 5.5 498511fd51 IR: Drop everything after a conditional exit folded to always taken
Only the ExitToConst right after it was skipped before.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:39:24 -06:00
Henrik RydgårdandClaude Opus 5.5 00f5e12b47 IR JIT: Don't store dead temps at exits
The IR temps don't live past the block, but FlushAll stored them anyway at
every exit (the branch operands, lwl/lwr temps, VFPU temp lanes). At an exit,
discard the ones nothing later in the block reads.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:38:39 -06:00
Henrik RydgårdandClaude Opus 5.5 a99a82cc6b IR: Keep more constants known in PropagateConstants
- A constant stays known after it's written out for a read (by a store,
  MovZ, a multiply...), so later uses still fold. Whatever an op writes is
  forgotten after its inputs are written, and setting a reg to the value it
  already holds isn't written twice.
- A conditional exit that isn't taken keeps the constants known.
- The saturating and min/max FP ops, FSign and the 31-bit Vec2 pack/unpack
  no longer flush every GPR constant.
- A load through its own base is folded (lui v0, hi; lw v0, lo(v0)).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:35:11 -06:00
Henrik RydgårdandClaude Opus 5.5 25e8f1d57c IR: Fix lwl/lwr pairing into the base reg, and sp validation past barriers
- An lwl/lwr pair was combined into one load even when the first half loads
  into the base register, which changes the address of the second half.
- ApplyMemoryValidation shared one sp check across the block even past an
  Interpret or CallReplacement, which may change sp.
- Drop a duplicate FSqrt meta entry, and name Load8Ext correctly.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:35:11 -06:00
Henrik RydgårdandClaude Opus 5.5 1dbb62d570 IR: Fix PurgeTemps miscompiles
- Copy propagation through an FPR temp didn't stop when an instruction
  rewrote the temp in place (it compared an FPR number against the +32
  offset reg), so later reads lost that write.
- A read of the temp in both operands only had src1 replaced, yet the copy
  into the temp was still removed.
- The replacement matched operands by number without checking their type,
  so a StoreFloat whose GPR address had the temp's number got its address
  replaced (IRVTEMP_PFX_S and IRTEMP_0 are both 192).
- A write to lanes 1-3 of a Vec4 temp wasn't noticed.
- IRReadsFromFPRs stopped after the F operands, missing Vec4Scale's vector.
- Exits and barriers didn't count as reading everything, so a write to a
  real reg could be moved above an exit.
- Load32Linked and Store32Conditional were removed when their reg was
  overwritten unread, losing LLBIT and the store.

Also fixes an off-by-one in the vec src3 read check. The unit test now
reports every failing case instead of stopping at the first.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:35:11 -06:00
Henrik RydgårdandClaude Opus 5.5 f8004442c8 RISC-V IR: Allocate the saved registers before the temporaries
After the registers usable by compressed instructions, prefer s2-s7 and
fs2-fs11, so that fewer values have to be flushed around calls. The
dispatcher already saves them.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:41 -06:00
Henrik RydgårdandClaude Opus 5.5 c38d04a10c RISC-V/LoongArch IR: Get vrot's sine and cosine from one call
Like arm64 and x64, call vfpu_sincos_packed and split the double it returns.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:41 -06:00
Henrik RydgårdandClaude Opus 5.5 f92340c092 IR: Compute vrot's sine and cosine in one call
A new FSinCos op writes both from one argument reduction. arm64 and x64 get
both back from a single call, packed in one double; RISC-V and LoongArch make
the two calls.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:41 -06:00
Henrik RydgårdandClaude Opus 5.5 6fc4eb19df VFPU: Fix vrot with the angle in a destination lane
The cosine is then taken of what vrot wrote to that lane: the sine, or zero.
The IR looked at the sine lane instead of the lane holding the angle, and the
legacy JITs ignored the overlap. The assembler refuses such a vrot, so those
now leave it to the interpreter, and don't pair one with the vrot before it.

Covered by the new cpu/vfpu/vrot test.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:41 -06:00
Henrik RydgårdandClaude Opus 5.5 4ebf9ed037 LoongArch JIT: Flush LSX vectors in F24-F31 before calls
The ABI only preserves the low 64 bits of F24-F31, which are first in
the allocation order, so a four-lane vector there lost its upper half
across a call to a math helper. Flush those like arm64 does for
S8-S15.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:22 -06:00
Henrik RydgårdandClaude Opus 5.5 46ae865b95 x86 JIT: Call the VFPU math helpers without the full thunk
The thunk saves a fixed set of registers and MXCSR on every call. The
math helpers (vrcp through vrexp2, and vrot's sincos) leave MXCSR alone,
so they now go through CallProtectedLeaf, which saves only the
caller-saved registers the caches are using, around a direct call. vrot
also no longer flushes everything first. x86-64 only; 32-bit x86 keeps
the thunk.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:22 -06:00
Henrik RydgårdandClaude Opus 5.5 77ff1578c4 x86 JIT: Don't save callee-saved registers in the call thunk
ProtectFunction's thunk saved all of XMM2-15 and RBX around every call,
but the callee preserves XMM6-15 on Windows and RBX everywhere. On
Windows that drops ten 16-byte saves and loads from each protected call.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:22 -06:00
Henrik RydgårdandClaude Opus 5.5 f7ba67405d arm64 JIT: Keep S8-S15 mapped across VFPU math calls
Values in S8-S15 survive a call, but the full flush wrote them back and
the following instructions loaded them again. The VFPU math callouts,
vrot and vh2f now flush only the caller-saved registers, plus the few
callee-saved ones they stage values in, and map the destinations
afterwards. In a normalize loop with sixteen VFPU registers live, that
takes a vrsq.s from about 15 to 11.5 ns.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 16:22:22 -06:00
Henrik Rydgård bd8e321137 Merge pull request #22350 from hrydgard/jit-missing-ops
JIT (all of them): Fill out various missing ops
2026-09-24 16:05:35 -06:00
Henrik RydgårdandClaude Opus 5.5 8f804d6f0f Document the LoongArch LSX lane trap and testing under qemu
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 15:42:38 -06:00
Henrik RydgårdandClaude Opus 5.5 79e4568e50 LoongArch JIT: Leave the Vec2 packs to the interpreter with LSX
With LSX a lane group can be mapped as one vector reg, and F() then returns
the same reg for every lane, so the per-lane code wrote only lane 0 (vs2i,
vus2i). Also drop the stale aliasing TODOs; each path reads its sources first.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 15:39:39 -06:00
Henrik Rydgård be22f0270b Merge pull request #22348 from hrydgard/atrac-decode-latency
Atrac: Write decoded samples when sceAtracDecodeData returns, not when called
2026-09-24 15:17:52 -06:00
Henrik RydgårdandClaude Opus 5.5 ff7371dcc5 Atrac: Write decoded samples when sceAtracDecodeData returns, not when called
On a PSP the Media Engine decodes, and the samples land in the output
buffer as the call returns, a couple of milliseconds in. We wrote them at
once and only then delayed the thread. Since sceAudio plays straight out
of game memory, that matters: Fired Up decodes each chunk to 0x40 bytes into
one of its two buffers, running over the first 16 samples of the other one,
which it has just queued, and relies on the mixer having read those first.
Writing early replaced them about 21 times a second, which is the constant
crackle in its music and intro (it showed up with the sceAudio buffering
rework, which stopped copying buffers at enqueue).

Now the decoder's output is set aside, the old contents put back, and a
CoreTiming event writes the samples just before the thread wakes. Pending
writes are kept in savestates.

Adds audio/blocking/parked, recorded on a PSP: a blocking output that had
to wait returns before any of its buffer has played, so the game really
does depend on the decode's latency.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:49:09 -06:00
Henrik Rydgård 3d859bf7cc Merge pull request #22347 from ygordreyer/fix/umineko-texture-hash
Fix stale glyphs in swizzled CLUT4 atlases
2026-09-24 14:45:20 -06:00
Henrik RydgårdandClaude Opus 5.5 d1a8ce0dcc IR: Compile vmscl on any size and transposition
Only 4x4 with source and destination transposed alike, and a scale
outside the destination, compiled; most vmscl in games are transposed
or 3x3. The rest now multiply element by element, with the scale
copied first, and only a partly overlapping source still falls back.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 b87533a128 arm64 JIT: Compile ll/sc, and vcmp EN/NN/ES/NS with vs != vt
ll and sc always went to the interpreter; a few games use them
thousands of times. They now load and store directly with fast memory,
keeping llBit in MIPSState. vcmp's NaN and inf-or-NaN tests only look
at s, so they no longer need vt to be the same register: EN and NN
compare s with itself.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 d9eab0968a RISC-V JIT: Compile the bit ops and min/max without Zbb
Without the Zbb extension, clz, rotr, wsbh, wsbw, bitrev, min and max
went to the IR interpreter, and wsbh always did. They're now base ISA
sequences: a branchless binary search for clz, paired shifts for the
rotates and byte swaps, mask-and-shift steps for bitrev, and a
compare-and-branch for min and max. Checked against a model of the
instructions over random inputs, since nothing here runs RISC-V.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 9def690781 IR: Compile vt4444, vt5551 and vt5650
They always went to the interpreter. Each channel is now a shift, mask
and shift in the existing integer ops, so every backend handles them.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 6b78138c08 VFPU: Compile vh2f in the IR, and call vfpu_h2f for it everywhere
vh2f always went to the interpreter in the IR. A new FHalfToFloat op
converts the lower or upper half of a word, and the native backends
call vfpu_h2f for it like FSin. The legacy arm64 JIT now makes the same
call instead of computing the conversion inline; vh2f is rare, and the
call is much less code.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 ebd279fa70 arm64 JIT: Compile vh2f, vt4444/5551/5650, vbfy, vmscl, vcrs and vdet
All went to the interpreter. vh2f works in integers to match vfpu_h2f,
since FCVTL neither flushes subnormal halves nor keeps inf/NaN mantissa
bits unshifted. The color conversions are bitfield extracts and inserts.
vbfy, vcrs and vdet follow the IR frontend, and vmscl scales element
by element. Results go through scratch registers, so a destination that
overlaps a source is fine.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 eaf55c467b IR: Fold ClampToZero into the 31-bit packs
Vec4ClampToZero and Vec2ClampToZero only ever fed Vec4Pack31To8 and
Vec2Pack31To16, for vi2uc and vi2us. The packs now clamp negative lanes
to zero themselves, which saves an op and a vector temp, and lets x64
clamp with PACKUSWB's saturation after an arithmetic shift.

While at it, RISC-V compiles Vec2Unpack16To31, Vec2Pack31To16 and
Vec4Pack32To8, and LoongArch Vec2Unpack16To31, Vec2Pack31To16 and the
non-LSX Vec4Pack32To8, all of which went to the IR interpreter.
LoongArch's Vec2Pack32To16 and Vec2Unpack16To32 now take their scalar
path with LSX too, instead of falling back.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 3db7c65e86 x64 IR JIT: Compile the VFPU pack, unpack and clamp ops
vi2uc, vi2c, vi2us, vi2s, vuc2i, vc2i, vus2i and vs2i lowered to IR ops
that x64 left to the IR interpreter. They're now SSE2: shifts into
place, then PACKSSDW/PACKUSWB for the packs and self-unpacks for the
unpacks. An output overlapping its input still goes the slow way.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 dd416656a7 RISC-V/LoongArch JIT: Compile cvt.w.s
FCvtWS always went to the IR interpreter. Both now convert in the
current rounding mode, which ApplyRoundingMode keeps at the game's, as
x64 does. RISC-V's FCVT already saturates and gives INT_MAX for NaN;
LoongArch patches NaN to INT_MAX like its FRound.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 0c44852c9e LoongArch JIT: Compile min and max
They always went to the IR interpreter. Now a signed compare-and-branch
on the normalized sources picks which one to move.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik RydgårdandClaude Opus 5.5 8661fbf8ce arm64 JIT: Compile vf2i, vsgn, vslt, vsge and vcmp EI/NI
These went to the interpreter. vf2in/vf2iz/vf2iu/vf2id use FCVT, which
saturates like the PSP, and patch NaN to 0x7FFFFFFF like the IR
backend. vsgn keeps the sign bit on 1.0 and gives 0 below the smallest
normal. vsge and vslt select 1 or 0 on a compare whose condition is
false when unordered. EI and NI test |s| against infinity in integers.
All match the interpreter on special values, ties and denormals.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-24 14:31:22 -06:00
Henrik Rydgård 319fbedabf Merge pull request #22346 from hrydgard/macosx-fixes
MacOSX: Menubar fixes, compile warning fix
2026-09-24 14:27:24 -06:00
Henrik Rydgård 19f57ec438 Merge pull request #22345 from hrydgard/use-vfpu-interpolator
Use the new VFPU special-function implementations globally
2026-09-24 14:27:09 -06:00
Ygor Dreyer a422b818b7 Hash full swizzled CLUT4 glyph atlases 2026-09-24 17:10:10 -03:00