Commit Graph
15061 Commits
Author SHA1 Message Date
Henrik Rydgård 67f2bf57cb RamCachingFileLoader: don't round a mid-file short read up to a full block
blocksActuallyRead rounded bytesRead up to the next whole block
unconditionally, intending to handle the legitimate case where the
very last block of the file is naturally shorter than BLOCK_SIZE
(cache_ is deliberately over-allocated for that). But it applied the
same rounding to any short read, including a genuine failure or a
dropped connection mid-file (this loader can sit on top of the whole
Remote ISO chain via CachingFileLoader/HTTPFileLoader when "Cache full
ISO in RAM" is enabled) - marking a block as fully cached when only a
few of its bytes were actually written. Since cache_ is malloc'd (not
zeroed), every later read of that block would serve uninitialized heap
memory as if it were real file data.

Only round up when the short read's end position exactly matches the
true end of the file.
2026-08-11 08:54:16 +02:00
Henrik Rydgård f7f92c5db7 DiskCachingFileLoader: fix partial-read caching, index bounds, and offset bug
SaveIntoCache checked `readBytes != 0` instead of comparing against the
full expected length, so any nonzero-but-short read from the backend
(e.g. a Remote ISO connection dropping mid-file) was treated as a
complete success: in the multi-block path this marked *all* requested
blocks (up to 16) as fully cached and wrote the uninitialized tail of
the read buffer to the on-disk cache file, and in both paths the
short/uninitialized data was also copied straight into the caller's
output buffer and counted in the return value - so a read failure was
reported (and permanently cached) as success. Only treat a block as
read once the backend actually delivered the full blockSize_ for it,
and stop before caching or returning anything for blocks it didn't.

Also fixes two latent bugs in the same functions, unreachable in the
current call graph (DiskCachingFileLoader is only ever driven by
CachingFileLoader, which always issues block-aligned reads) but wrong
if ever called otherwise:
- The multi-block loop reused the batch's initial `offset` (the
  position within the *first* block) for every subsequent block
  instead of resetting it to 0, which would both read from the wrong
  place in `wholeRead` and mis-copy less than a full block for i > 0.
- ReadBlockData() applied `offset` to the destination pointer instead
  of the file seek position, which would both read the wrong bytes
  from disk and write up to `offset` bytes past the end of the
  caller's buffer.

LoadCacheIndex's sanity check on persisted block indices used `>`
instead of `>=` against maxBlocks_ (blockIndexLookup_ only has
maxBlocks_ entries, valid indices 0..maxBlocks_-1), so a corrupted
cache file's index entry with block == maxBlocks_ exactly would pass
validation and then index one past the end of blockIndexLookup_.
2026-08-11 08:54:16 +02:00
Henrik Rydgård 7e64052914 CachingFileLoader: don't cache blocks the backend failed to fully read
SaveIntoCache() discarded backend_->ReadAt()'s return value entirely
and unconditionally marked the requested block(s) as cached. A short
or failed read from the backend (e.g. a Remote ISO connection dropping
mid-file, now that LocalFileLoader/RetryingFileLoader correctly report
failures as 0 rather than a huge count) would still get stored as a
"valid" cached block, permanently serving its uninitialized tail as if
it were real file data on every later read, with no retry.

Only insert a block once we've confirmed the backend actually
delivered the full BLOCK_SIZE for it.
2026-08-11 08:54:16 +02:00
Henrik Rydgård 1671814be1 LocalFileLoader: report 0, not a huge bogus count, on read failure
ReadAt()'s contract is to return the number of bytes/units actually
read. On every platform branch, an OS-level read failure (ReadFile
returning FALSE, or pread/read returning -1) was fed straight into a
division by `bytes` without checking for it first:
- Windows explicitly returned (size_t)-1.
- Elsewhere, the signed -1 from pread/read was implicitly converted to
  size_t (via the usual arithmetic conversions with the unsigned
  `bytes`) before the division, producing a huge bogus count instead
  of a small one.

Every caller in the caching chain (CachingFileLoader,
RamCachingFileLoader, RetryingFileLoader, ZipFileLoader's libzip
source callback) loops on "did we get at least what we asked for",
which a huge return value trivially satisfies - so a local I/O error
(removable media ejected, a content-URI permission problem mid-read,
etc.) would be reported as a fully successful read of whatever
uninitialized memory happened to be in the destination buffer.
2026-08-11 08:54:16 +02:00
Nemoumbra 5e9edb83ad Fixed passing 'timeout' to 'maxTries' in WebServer 2026-08-10 23:31:16 +03:00
James0124andClaude Opus 5 8afa18c21c sceFont: match hardware's glyph blending and destination combine
sceFontGetCharGlyphImage_Clip stored the glyph over the destination buffer.
Hardware adds it with saturation instead, so on hardware a glyph never erases
what was already in the buffer - the transparent parts contribute zero - while
we cleared them to 0. Text drawn as overlapping glyphs lost the earlier ones.

Measured on a PSP-1000 against a dumped ltn0.pgf, sweeping the pen position's
fractional part, both 4bpp and 8bpp, and several destination pre-fill values so
that "wrote a 0 here" could be told apart from "did not write here":

- The result is min(dst + blend, max), not blend.
- The two horizontal weights are rounded in opposite directions, down for the
  left neighbour and up for the pixel itself. That is not a free choice: it is
  what makes the pair sum to exactly the format's full scale whenever both
  samples are full ink, for every fraction. Rounding the combined sum once, as
  before, disagrees with hardware on about a fifth of the blended pixels.
- 4bpp blends the raw nibble and 8bpp the value swizzled to 8 bit. Blending at
  8 bit and narrowing afterwards is not the same thing and misses ~0.6%.
- The fractional part of yPos64 is discarded entirely. There is no vertical
  blending and the rectangle never grows downwards, so renderY2 loses its +1
  and the two render loops collapse into one - xFrac == 0 needs no special
  case, the first term vanishes and the second collapses to exactly b.

Only PSP_FONT_PIXELFORMAT_4 and _8 render at all. _4_REV, _24 and _32 return 0
and leave the buffer completely untouched, which is also the answer to the
"not sure how to make these produce an image" note in pspautotests'
charglyphimageclip.cpp. They are skipped now, with a report so that a game
relying on them can be found - only one buffer configuration was measured.

Verified with pspautotests: the new charglyphimagexfrac goes from 388 of 601
differing lines to passing, and charglyphimage and charglyphimageclip improve
from 57 differing lines to 3. No other font test changes. The remaining 3 are
a separate, pre-existing issue with bytesPerLine of 0 and 1.

Not covered: clip rectangles that actually clip, negative pen positions, and
the shadow glyph entry points.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-10 19:49:55 +09:00
Henrik Rydgård 914e4e4cab Merge pull request #22069 from hrydgard/read-u32-cleanups
Tech debt: Start cleaning up HLE memory access
2026-08-10 12:09:50 +02:00
Henrik Rydgård 6540a29180 Merge pull request #22067 from hrydgard/networking-work
Fix some WinSock error code problems, fix error logic in InputSink (networking)
2026-08-10 11:25:46 +02:00
Henrik Rydgård a1f027bf84 Merge pull request #22057 from hrydgard/frametest-on-ci
Add a minimal framedump-render test system for CI
2026-08-10 11:24:42 +02:00
Henrik Rydgård 7824f69020 Code style updates 2026-08-10 11:17:58 +02:00
Henrik Rydgård e2bc017112 More removals of Read_U32 2026-08-10 11:17:45 +02:00
Henrik Rydgård 2d208ca7d9 Remove Read_U32 from sceKernelMutex 2026-08-10 11:02:25 +02:00
Henrik Rydgård b42157aa49 Core: Add utility function to properly report memory exceptions from HLE functions (when they would actually crash the PSP) 2026-08-10 10:41:32 +02:00
Henrik Rydgård 66c8bfbcb2 Improve semantics 2026-08-10 10:11:24 +02:00
Henrik Rydgård 933751e2a9 Windows: Avoid POSIX error codes leaking into our WSA socket error codes 2026-08-10 10:04:21 +02:00
Henrik Rydgård abb57c620f Adjust some log levels 2026-08-09 22:10:54 +02:00
Henrik RydgårdandClaude Sonnet 5 dcf742edb4 Dsable AndroidHwScale by default
AndroidHwScale defaults to 0 instead of the old device/resolution-based heuristic (which is
removed along with DefaultAndroidHwScale()).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4QAoxV2KY7ek4PcZw3WvY

...
2026-08-09 19:03:08 +02:00
Henrik Rydgård 07e63c345c Add SAVE_STATE to BrowseFileType 2026-08-09 19:03:08 +02:00
Henrik Rydgård 63ef2a7498 Hide savestate controls if you are running a frame dump 2026-08-09 19:03:08 +02:00
Henrik Rydgård b0f070040b Don't auto-enable logging in debug mode in headless, it's annoying. 2026-08-09 13:41:39 +02:00
Henrik Rydgård 8c9bf04add Headless: force opaque PNG screenshots by default, add --screenshot-keep-alpha
Games often use the framebuffer alpha channel for non-visual purposes,
so saved PNGs could look fully transparent in image viewers. Force alpha
to 255 when writing PNG screenshots unless --screenshot-keep-alpha is
passed. The MSE comparison ignores alpha either way.
2026-08-09 13:41:39 +02:00
Henrik Rydgård 893ac3e3db Frametests: add framedump rendering test runner and PNG screenshot support
- Add frametests.py: walks a dump tree, renders each dump per config variant
  through PPSSPPHeadless, generates reference images when missing and compares
  MSE when present, and writes a self-contained HTML report. The JSON config
  (which lives with the test set, not in the repo) points at the data tree
  and defines variants as suffix -> CLI args, e.g. 'soft': '--graphics=software'.
- Headless: --screenshot-save saves PNG when the path ends in .png; new
  --screenshot-diff always writes a visual comparison when comparing;
  screenshot comparison failures (mismatch or unloadable reference) now fail
  the test instead of passing silently.
- Read back framebuffers top-down, flipping only for BMP output/input
  (fixes upside-down PNG references). Sync libretro copy accordingly.
- Document the system in docs/frametest.md; add AGENTS.md reference.
2026-08-09 13:41:39 +02:00
Henrik Rydgård 8cd7e1b2c0 Delete all support for Qt
Our Qt backend has long been left behind and doesn't even support Vulkan
currently. There would be a lot of work to make it viable, and I don't
think anyone is really interested.

ImGui on SDL will soon fulfill the need for a more classic user interface
with a menu bar on Linux, and on Mac we already have a native UI.
2026-08-08 18:18:28 +02:00
Henrik RydgårdandClaude Sonnet 5 3500293402 SymbolMap: route remaining GUI-thread callers, remove internal locking
Windows/MainWindowMenu.cpp's Load/Save/Clear Symbol Map menu actions
mutated g_symbolMap directly from the WinMain thread; route them through
Core_RunOnCPUThread like the rest of the debugger. Windows/MainWindow.cpp's
WM_USER_GET_MODULE_INFO handler read it directly too; guard with
g_frameMutex. Windows/main.cpp's SortSymbols() calls turn out to already be
safe as-is - both notifications that trigger them (BOOT_DONE,
SYMBOL_MAP_UPDATED) are only ever fired from the CPU/NativeFrame thread -
so just fix the stale comment claiming reliance on the (now removed)
internal lock.

With those covered, every remaining caller is either on the CPU/NativeFrame
thread already or routes through Core_RunOnCPUThread/g_frameMutex, so
SymbolMap's internal recursive_mutex is redundant - remove it and all ~40
lock_guard call sites. Qt's mainwindow.cpp still pokes at g_symbolMap
directly and unguarded (a pre-existing issue, out of scope - Qt isn't a
maintained backend), but removing the lock doesn't change its public API,
so it still builds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 17:22:12 +02:00
Henrik RydgårdandClaude Sonnet 5 5df8c14f1e Core_RunOnCPUThread: drain the queue from NativeFrame(), not just Core_RunLoopUntil()
Core_RunLoopUntil() is only reached while a game is actually loaded and
running (via EmuScreen). Anything calling Core_RunOnCPUThread() while at
the main menu with no game loaded would hang forever waiting for a queue
that was never drained. Call Core_ProcessCPUQueue() directly from
NativeFrame(), just before screenManager->render(), so it always runs;
Core_RunLoopUntil() still also drains it for the tight-spin-while-stepping
case once a game is running.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 17:22:12 +02:00
Henrik RydgårdandClaude Sonnet 5 180becf883 BreakpointManager: remove internal locking, now redundant
Every caller either runs on the CPU thread already, routes mutations
through Core_RunOnCPUThread, or holds g_frameMutex for reads - audited
across WebSocket subscribers, the legacy Win32 debugger, ImDebugger, and
the JIT/interpreter backends. Also renames GetMemCheckLocked to
FindMemCheckInRange since it no longer implies a lock is held.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 17:22:12 +02:00
Henrik RydgårdandClaude Sonnet 5 f72709feb0 Legacy Win32 debugger: fix the painting problem with a frame-scoped mutex
Debugger windows (register list, disassembly view, memory view, breakpoint/
thread/module/stack lists, watch list) read CPU-thread-owned state directly
from the GUI thread's WM_PAINT/list-fill handlers, racing against the CPU
thread. Routing every read through Core_RunOnCPUThread would be too slow for
something invoked continuously on paint/list-refresh.

Add g_frameMutex (Core.h/Core.cpp), held by NativeFrame() only across the
span where it actually touches that state (running the CPU, processing
breakpoints, running the ImGui debugger) - not across input handling or the
present/frame-pacing waits. Debugger windows now hold the same mutex while
reading, giving synchronized reads without the round-trip cost of queuing
to the CPU thread.

CtrlRegisterList::onPaint() goes back to always reading live values (now
safe under the lock) and grays them out by color alone while the core is
running, rather than the earlier snapshot-caching approach.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 17:22:12 +02:00
Henrik RydgårdandClaude Sonnet 5 03dcfd3931 WebSocket debugger: fail fast on invalid memory ranges, move base64 off the CPU thread
memory.read_u8/u16/u32/read/readString/write_u8/u16/u32/write/search all
validated their address/size parameters (and, for search, the rest of its
param parsing) after already queuing onto the CPU thread. None of that
depends on CPU-thread-owned state, so do it upfront instead and fail fast
without a round trip through the queue for requests we already know are
invalid.

Also, for memory.read and memory.readString, only the raw memory copy
(which needs replacements/emuhacks disabled) now happens on the CPU
thread - the base64 encoding itself happens back on the WebSocket thread
afterward, so a large read no longer blocks the CPU thread's frame pump
for the encoding work too.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 17:22:12 +02:00
Henrik RydgårdandClaude Sonnet 5 212ed7cdda Debugger: Route HLESubscriber through the CPU thread
Same treatment as the other subscribers: thread list/wake/stop, function and
data symbol list/add/remove/rename/scan, and backtrace now route their
kernel thread, symbol map, and disassembly manager access through
Core_RunOnCPUThread() instead of touching that state directly from the
WebSocket handler thread.

Memory::IsValidRange() checks that only depend on the request's own
address/size params (not on anything CPU-thread-owned) stay outside the
queued callback and fail fast, rather than making a pointless round trip
through the CPU thread for a request already known to be invalid.

hle.func.scan carries the same unbounded-range caveat already noted for
memory.search: no cap on 'size' beyond valid memory range.

Replaced remaining `auto` locals with concrete types.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 12:40:18 +02:00
Henrik RydgårdandClaude Sonnet 5 75b9df8384 Debugger: Route MemorySubscriber through the CPU thread, drop the forced-pause dance
Every memory.read*/write*/search endpoint used to call LockMemoryAndCPU(),
which - unless the CPU was already stepping - busy-waited for coreState to
settle, force-paused a running game with Core_Break(), and blocked on
Core_WaitInactive() before touching memory, just to get exclusive access
from the WebSocket handler thread. It also took MIPSComp::jitLock around
saving/restoring emuhack ops for the same reason.

Now the whole body of each handler runs inside Core_RunOnCPUThread(), so
none of that is needed for CPU-thread exclusivity: reads/writes happen
inline on the CPU thread itself, whether the game is running or stepping,
without ever pausing it. Confirmed live that memory reads/search now
complete while coreState stays CORE_RUNNING_CPU throughout - no more
stepping flicker on every debugger memory poll.

Kept Memory::MemoryInitedLock (guards against Memory::Shutdown() racing in
from a different thread, e.g. the UI thread stopping the game - unrelated
to the WebSocket-thread-vs-CPU-thread problem) and MIPSComp::jitLock around
the emuhack save/restore (guards against a UI-triggered CPU core switch,
also a different thread than the one Core_RunOnCPUThread targets).

Same caveats as previous conversions: memory.read for a very large 'size'
now base64-encodes on the CPU thread itself, and memory.search still has no
size cap - both will now block the CPU thread's own frame pump for their
duration on a large enough request. Noted inline, not fixed here.

Replaced remaining `auto` locals with concrete types.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 12:15:04 +02:00
Henrik RydgårdandClaude Sonnet 5 c32df3d931 Debugger: Route BreakpointSubscriber, DisasmSubscriber, and most of
CPUCoreSubscriber through the CPU thread

Continues the pattern started with SteppingSubscriber: route breakpoint,
disassembly, symbol, and register access through Core_RunOnCPUThread()
instead of touching that state directly from the WebSocket handler thread.

Two intentional exceptions, matching the reasoning already used for
cpu.stepInto's "not currently stepping" branch:
- cpu.stepping's Core_Break() call stays unqueued - it's what makes the CPU
  thread start reaching the queue drain point in the first place.
- cpu.status stays unqueued - it's meant to be a cheap, frequently-pollable
  status check, and its "pc" field is already documented as inaccurate unless
  stepping. Matches how SteppingBroadcaster already reads the same state
  directly from the WebSocket thread.

Where a handler's response doesn't depend on anything the queued lambda
computed (plain add/remove endpoints), moved req.Respond() back out after
the Core_RunOnCPUThread() call for readability - the JSON building and
socket write happen later in Finish() regardless of where Respond() is
called, so there's no thread-safety difference either way, just clarity
about what actually needs to run on the CPU thread.

memory.searchDisasm carries the same caveat flagged for memory.search: its
scan range has no size cap, so if the CPU is stepping, a very large range
will now block the CPU thread's own frame pump for the scan's duration
rather than running unqueued on the WebSocket thread as before. Not fixed
here - noted in a comment at the call site.

Replaced remaining `auto` locals in these three files with concrete types.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 11:56:32 +02:00
Henrik RydgårdandClaude Sonnet 5 29825c1e61 Debugger: Route the rest of SteppingSubscriber.cpp's handlers through the CPU thread
Extends the cpu.stepInto treatment to cpu.stepOver, cpu.stepOut, cpu.runUntil,
and cpu.nextHLE: each now routes its breakpoint/stepping manipulation through
Core_RunOnCPUThread() instead of touching it directly from the WebSocket
handler thread. cpu.runUntil didn't have an explicit "must be stepping"
guard to begin with; since the CPU-thread queue is now drained unconditionally
at the top of every Core_RunLoopUntil() iteration (not just while stepping),
queuing from it is safe regardless of current core state.

Also corrects a stale comment on Core_RunOnCPUThread() left over from before
the drain point moved from Core_ProcessStepping() to the top of
Core_RunLoopUntil() - it's not limited to the stepping/paused case.

Replaced remaining `auto` locals in this file with concrete types.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 11:32:01 +02:00
Henrik RydgårdandClaude Sonnet 5 c6fccefa49 Debugger: Route cpu.stepInto's stepping state through the CPU thread
The WebSocket debugger's cpu.stepInto handler ran entirely on the WebSocket
handler thread, directly manipulating breakpoints and stepping state (via
Core_RequestCPUStep, g_breakpoints.SetSkipFirst, etc.) that's otherwise only
ever touched from the CPU thread (the one that calls Core_RunLoopUntil, and
thus indirectly NativeFrame).

Adds Core_RunOnCPUThread() - queues a function to run on the CPU thread and
blocks the caller until it's done. The queue is drained at the top of
Core_RunLoopUntil()'s loop, so it's reached continuously (in a tight spin)
while the CPU is stepping/paused, and at least once per call even while fully
running.

cpu.stepInto is the first consumer: once the CPU is already stepping, the
breakpoint/stepping manipulation is now routed through Core_RunOnCPUThread
instead of happening directly on the WebSocket thread. The "not currently
stepping" path still calls Core_Break() directly from the WebSocket thread,
since it's already documented free-threaded and is what makes the CPU thread
start reaching the queue-drain point in the first place.

More WebSocket debugger commands can be converted the same way going forward.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 11:21:46 +02:00
Henrik RydgårdandClaude Sonnet 5 b1f0112cef Debugger: Remove opcode-fusion display and fix cpu step size units
DisassemblyManager used to fuse lui+addiu/load/store into single pseudo-
instructions ("li", fused loads/stores) for display. This only applied to a
handful of opcodes, complicated DisassemblyManager, and was the root cause of
a stepping bug: Core_PerformCPUStep's Into/Over cases treated stepSize as a
byte count, while the WebSocket cpu.stepInto handler computed it as an
instruction count (needed to step over a whole fused macro in one go) - so a
plain, non-fused stepInto silently executed zero instructions.

Removed the fusion logic entirely (DisassemblyMacro, DISTYPE_MACRO) - every
disassembly line is now exactly one 4-byte instruction. With that,
"how many instructions does this line span" is always 1, so the
getInstructionSizeAt() byte-size queries in the legacy Windows and ImGui
debuggers are gone too; step requests just pass 1. Core_RequestCPUStep's
stepSize is now consistently in instructions everywhere.

Also fixes the PPSSPPHeadless build, broken since 0ed1f3e added
OpenWebDebugger() (which calls System_LaunchUrl) without a headless stub.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm11k99viLfbJm2MkH4BH
2026-08-08 11:16:36 +02:00
Henrik Rydgård 0ed1f3eceb Add some easy ways to get into the web debugger 2026-08-08 10:13:09 +02:00
Henrik Rydgård a957086eeb Try to fix test failure (vary strange) 2026-08-08 00:45:11 +02:00
Henrik Rydgård 8d2c1e7a66 Make the ImDebugger a bit less crash prone outside of games 2026-08-07 22:40:05 +02:00
Henrik Rydgård b4c476d5ed Merge pull request #22048 from hrydgard/imgui-lift
ImDebugger: Lift it out of the EmuScreen
2026-08-07 19:13:13 +02:00
Henrik Rydgård 25532a9b64 Fix build error in iOS app store build. Also fix a log error. 2026-08-07 18:43:29 +02:00
Henrik Rydgård db8ff4391e Enable ImDebugger everywhere, on top of the regular UI. 2026-08-07 17:35:15 +02:00
Henrik Rydgård bb3862b37e Revert "Extend LoadExecForKernel with real VSH loadexec/exit syscalls"
This reverts commit 510cfb421c.
2026-08-07 16:01:27 +02:00
Henrik Rydgård c1310ae4a5 Rework UPnP service thread sync
No longer waking up twice per second. Instead a slow 5s poll plus
wakeups if needed.
2026-08-07 11:24:22 +02:00
Henrik Rydgård 256e4082eb Merge branch 'master' into avoid-strlen-memblockinfo 2026-08-07 10:44:55 +02:00
Henrik Rydgård d87a98c4a8 Avoid wasting CPU on counting characters in the memblock management
Unittest and a bugfix by claude.
2026-08-07 08:56:41 +02:00
Henrik RydgårdandClaude Sonnet 5 510cfb421c Extend LoadExecForKernel with real VSH loadexec/exit syscalls
Adds SceKernelLoadExecVSHParam (matching JPCSP's reference layout - its
first four fields line up with the existing SceKernelLoadExecParam,
which is why the plain sceKernelLoadExec already worked for
sceKernelLoadExecVSHMs2) and fills in the rest of LoadExecForKernel's
NIDs from JPCSP: real implementations for sceKernelExitVSHVSH/Kernel
(mirrors sceKernelExitGame) and sceKernelLoadExecBufferVSHUsbWlan (loads
an exec from an in-RAM buffer instead of a file - the VSH's "push a game
over USB/WLAN" path), plus UNIMPL stubs for everything JPCSP itself only
knows by NID.

sceKernelLoadExecBufferVSHUsbWlan needed __KernelLoadExec split into a
file-reading front end and a shared __KernelLoadExecFromPtr back end
that both it and the new buffer-based path call into - a pure
extract-method refactor of the single most heavily used boot path in the
emulator. Verified no regression: same 11 passed / 9 pre-existing-failed
split on pspautotests/tests/cpu/*, and loader/bss still passes, before
and after this change.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSNaZnHCjmryS3ziVN9gZU
2026-08-07 08:49:25 +02:00
Henrik Rydgård 5f5130025c Merge pull request #22037 from hrydgard/hide-status-bar-ios
Add setting to hide/show the status bar on iOS
2026-08-07 07:24:25 +02:00
Henrik RydgårdandClaude Opus 5 8bfc151395 iOS: Hide the status bar when immersive mode is enabled
prefersStatusBarHidden was dead code - it computed an orientation and a
(commented out) user preference, then unconditionally returned false. So the
status bar was only ever hidden on iPhone in landscape, and only because iOS
does that on its own in compact height.

Now it honors bImmersiveMode from the DisplayLayoutConfig matching the current
orientation, so it also applies in portrait and on iPad. Adds the corresponding
checkbox to the iOS system settings, and updates the status bar on rotation and
when the setting is toggled.

Also fixes a missing break in the ROTATE_UPDATED case in System_Notify, and a
static/non-static mismatch on sceKernelLoadModuleBufferUsbWlan that broke the
build (the header intentionally exposes it for sceVshBridge).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JZk5y4Fzw811WJoNWZb8Sc
2026-08-06 20:56:37 +02:00
Henrik Rydgård 092ab42fe7 Clean up ugly usage of the g_nativeLibDir global. Now it's local in VulkanLoader. 2026-08-06 18:12:04 +02:00
Henrik Rydgård 60fc887306 Clean up Config::PostLoadCleanup, reject disabled GPU backends 2026-08-06 17:45:37 +02:00
Henrik RydgårdandClaude Sonnet 5 5bd1ff8066 Move remaining manual command line parsing into CmdLine.cpp
Headless.cpp, NativeApp.cpp, and SDLMain.cpp each still hand-parsed a few
argv flags directly (mount/log/state/ignore/loglevel in headless and the
app, xres/yres/dpi/scale in SDL), duplicating and in some cases conflicting
with the shared CommandLineOptions parser. Consolidate all of it into
CmdLine.cpp/.h so there's a single source of truth, and drop the now-dead
remain_argc/remain_argv filtering in SDLMain.cpp since NativeInit no longer
reads argv itself.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PfFvWzpHxErWgRhKqqSewN
2026-08-05 16:02:49 +02:00