Commit Graph
57 Commits
Author SHA1 Message Date
Mihawk 0bca2863e6 Gates: test stubs for frame generation; comment wrapping; TLS and password patches renumbered 0129/0130
- tests/input_ps5_test.cpp: ps5_fg_record_request stub (the pad script's
  RECORD calls PS5_FrameGen's recorder, not linked in the host test).
- tests/test_webui_qr.py: stubs for the frame generation entries 0120 binds
  beside the WebUI's (ps5_fg_menu_is_label/_is_folder, action_ok_ps5_fg,
  action_ok_push_default).
- src/main.cpp, src/ps5_framegen_menu.c: tools/lint-format.sh --write
  (comments re-wrapped to the line limit; no code changed).
- The frame generation code already names patches 0122-0128, which
  patches/series does not list; 47879d1's TLS and password patches took
  0122/0123 and are now 0129 (TLS verification) and 0130 (password).

lint-format PASS; tests test_input_ps5, test_webui_qr, test_frontend,
test_webui_secrets: OK.
2026-10-14 19:27:23 -04:00
Mihawk 5b2dc7f42c FrameGen: blocking-core protocol, floor opt-in, mvsplat in the build, recorder width hook
apply-port-patches 0122-0128: private env commands 0x25001 (the core blocks inside retro_run) and 0x25002 (emulated vsyncs a frame
covers, period in microseconds) size the generator's group from what the core says, never from a measured gap; the floor is opt-in
(PS5_FRAMEGEN_FLOOR=1); core run/cpu times in the log. The menu and its config follow. build-retroarch.sh compiles fg_splat.cpp.
main.cpp reads framegen-record-width.txt for the recorder. input_ps5.cpp: reflowed comments and calls.
2026-10-13 08:50:58 -04:00
Mihawk 0b581dd6b8 Frame generation menus: XMB leftmost tab, RGUI first entry, ES-DE settings entry (0120)
Options (on/off, output rate, method, cadence, working size, status on screen) are shared
through /app0/config/framegen.cfg, which the title appends when it starts RetroArch.
2026-10-10 23:27:48 -04:00
Mihawk 9096eedb9b Test switch: how many frames the generator dumps 2026-10-10 22:48:01 -04:00
Mihawk e19c2f31b7 Test switch: /app0/framegen-dump.txt dumps the frame generator's frames 2026-10-10 21:42:42 -04:00
Mihawk b9260ae31c Keep existing installation paths usable after optional elevation
Request cooperative SDK elevation before RetroArch workers only when the
qualified external daemon is ready. Verify UID and executable identity, map
legacy filesystem paths, and retain shell LoadExec names. Picker and ES-DE
keep their normal sandbox startup. Missing daemon remains a normal launch.

Verification: tools/verify.sh format unit build integration evidence, run
with the pinned picker template. Format passed; 193 unit and 193 integration
tests passed; all shipped targets built; 123 evidence captures replayed.
Generated picker bootstrap repairs and earlier failed trials are recorded.

Console: console_test.py final-return-ra, final-esde and final-offline;
executables read-back verified; current settings preserved; test controls
removed. Badge PNG downloaded and decoded. Hosting reached player 2 once;
joining and account authentication remain unresolved. No WAN/lobby claim.
Artifact: evidence/installed-paths/{capture,expectation}.json and README.txt.
Reproduce comparison: bash tools/verify.sh evidence.

Pre-existing networking/updater/runner edits remain outside this commit;
the capture identifies the tested working-tree context.
2026-10-10 10:04:27 -04:00
Mihawk 6fa72d46e7 Content: a folder for every system the installed cores run
content/ had only the folders people made (and a bare "Saturn"), so a fresh install
gave no hint where games go (issue 33). ps5_library_make_system_folders makes
content/<system> for each system the installed cores' databases name, with RetroArch's
names ("Nintendo - Nintendo Entertainment System"), which every frontend's library
reads as that system. A system with a folder already, under any name ("PS1",
"Genesis"), gets none: nothing is renamed or moved. A database no platform stands for
(Satellaview, Sufami Turbo, PICO, CD32, CDTV) gets none; variants go to their system
(Wii (Digital) -> Nintendo - Wii).

- src/main.cpp runs it at each title start, before the frontend dispatch (a home-screen
  launch goes to the picker from there; RetroArch's own init is too late), so a core
  added later gets its folder.
- tools/system-folders.c runs the same code on the staged title in build-title.sh:
  dist/PPSA99169/content holds the 46 folders of the 33 cores; video-assets.py keeps
  empty folders in the release ZIP.
- The bare content/Saturn the title made is dropped (Sega - Saturn replaces it).

Evidence: evidence/issue-33-system-folders (console: 45 folders -> 52 after a home-screen
restart, the 7 missing systems added 0777, the owner's kept; dist and the ZIP: 46);
tests/ps5_library_test.c (10 made, an existing folder honoured, unknown databases and
cores without .so skipped, a second run makes none). tools/verify.sh: PASS (format unit
build integration evidence).
2026-10-09 22:29:13 -04:00
Mihawk d2d85c535c WebUI: its own daemon, up across every frontend; downloads read in blocks
The WebUI only ran inside RetroArch: a frontend change (LoadExec) ended it with
every upload in flight. It is now a payload of its own (daemon/webui_daemon.cpp,
webui/ps5-retroarch-webui.elf) serving the title's folder on 6769. eboot.bin, the
picker and ES-DE each keep a link to it (src/webui_link.h, 127.0.0.1:6770) and the
first to find none starts it through the ELF loader (9021) or websrv (8080 /hbldr).
It stops 20 s after the title closes, never mid-transfer; an update's Install
closes the title and the daemon installs. With no loader, eboot.bin serves the
WebUI while RetroArch runs, as before. The page names the frontend shown.

Downloads were handed to MHD as a descriptor (sendfile), which stopped at 33,300
bytes on the console; they are read in 256 KiB blocks.

Evidence: evidence/webui-daemon (base PS5 13.40). 200 MiB upload across picker ->
RetroArch -> picker and 60 MiB across picker -> ES-DE: one token throughout, 201
Created, every 256 KiB block equal on the console; daemon stopped 20 s after the
title closed; a 1,917,648,896-byte download's sha256 equals the FTP copy.
Command: tools/run-title.sh --picker-test=600:retroarch --retroarch-frames=1800
--watch 110 with build/tmp/webui-handover.py; tools/verify.sh: all five PASS.
Host tests: tests/test_webui_link.py, tests/test_webui_daemon.py.
2026-10-07 07:41:51 -04:00
Mihawk 4812ffdee0 FTP: everything in the title folder is 0777, and the repair finishes
Users reported FTP permission refusals again. Since v0.6.7 the title usually
hands itself over at once (to the picker or ES-DE, through LoadExec, which ends
the process), so the start-up repair that opens /app0 to FTP was cut short; and
the picker and ES-DE, other executables, wrote with their own modes.
- Files are 0777 as folders are (were 0666): the link-time wrappers and the
  repair (src/permissions_ps5.cpp).
- ps5_permissions_settle waits for the repair (at most a minute) before every
  handover: to a frontend, closing the title, the relaunch test.
- ES-DE's library files and folders, the remembered frontend
  (src/ps5_frontend_choice.h) and the picker's test record are 0777; the picker
  opens RADV's shader cache to FTP after its first 30 frames and again when it
  hands over.

Verified on the base PS5: the trace reads "permissions: /app0 checked=17992
repaired=174 refused=0" then "handover waited 596.2 ms"; after a home-screen
launch held at the picker and closed there, an FTP walk of
/data/homebrew/PPSA99169 finds 17992 entries, 0 not 0777 (before: 175 files
at 0666) (evidence/permissions-0777). tools/verify.sh format, unit and
evidence PASS.
2026-10-07 00:00:46 -04:00
Mihawk c861d36600 Frontends: a remembered choice, a quit that closes, logs per session and mode
Three of the frontend follow-ups in docs/FRONTENDS.md:

- The frontend the title starts with is remembered in config/frontend.cfg
  ("ask", "retroarch" or "es-de"; src/ps5_frontend_choice.h, shared by
  eboot.bin, the picker and the WebUI). The picker's Square switches
  Remember, which writes the frontend started, or "ask". The WebUI's
  quick panel has "Start with", kept in that file, never in webui.cfg.
  A launch from the home screen then starts that frontend directly.
  Holding L1 while the title starts opens the picker anyway: the first
  user's pad is read for up to a second before anything opens it
  (src/frontend_hold_ps5.cpp).
- A frontend that quits now says so: ES-DE and the picker-started
  RetroArch restart eboot.bin with --ps5-mode=quit. That shows the picker,
  or closes the title when a frontend is remembered.
- Logs: a launch with no --ps5- argument starts a session, and keeps the
  previous session's trace as trace.1.txt. RetroArch logs a game-mode game
  to retroarch-game.log and its own sessions to retroarch.log, each with
  its previous copy (.1). ES-DE keeps its last stdout.txt, and starts
  es-de-ps5.log again past 512 KiB.
- An update installed as RetroArch quits no longer hands over. Its
  files are already in place, so the title closes rather than start the
  new picker or ES-DE from the old process.

tools/run-title.sh: --picker-test takes :remember or :forget; with
--home-launch the title starts as from the home screen (no test-run
marker); a game-mode run's log is checked in retroarch-game.log.

Evidence: evidence/frontend-launch/ (capture.json, expectation.json).
Base PS5 13.40, build 584d4d27:
  game mode: the game logged to retroarch-game.log, and the trace held
    only this session (the rest in trace.1.txt)
  picker test with Remember on: frontend.cfg "es-de"
  home launch: L1 read (not held, decided at once), started ES-DE; ES-DE
    quit, and the title closed by itself
  the console's WebUI: frontend_start es-de, set to ask (200); the next
    home launch opened the picker
Holding L1 on a real pad was not exercised by a script. An installed
update closing the title is covered by the host test only.
Host tests: frontend_mode_ps5 and test_webui PASS.
Command:
  tools/run-title.sh --picker-test=300:es-de:remember --frontend-capture=20 --watch 50
  tools/run-title.sh --no-build --no-deploy --home-launch --frontend-capture=8 --frontend-quit --watch 40
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 22:06:36 -04:00
Mihawk 4788d35076 Up to four controllers, one per signed-in PS5 user
The console pairs each controller with a signed-in user, and scePadOpen
opens a user's controller, so RetroArch read only the first player's.
The joypad driver now connects controllers the way ProsperoEden does
(PS5_ProsperoEden b919847, headless/pad.cpp):

- Port 0 (player 1) is the user who started the title, and stays theirs.
- About once a second sceUserServiceGetLoginUserIdList is read again. A
  new user's controller takes the first free port (1 to 3); a port is
  let go, and announced gone, when its user signs out. A pad the process
  already holds is reused through scePadGetHandle.
- Each port is announced to RetroArch's autoconfiguration on its own and
  has its own buttons, axes, rumble and haptic stream. The pad script
  still plays port 0.

The console's config already maps players 1-4 to joypad indexes 0-3.
For test runs, tools/run-title.sh --pad-monitor arms
/app0/pad-monitor.txt, which traces each port's whole button word as it
changes, including the bit that says the system holds the controller.

Evidence: evidence/multi-controller/ (capture.json, expectation.json;
console user ids masked). On the base PS5 13.40 with two DualSense
controllers and two signed-in users (build 95a82988):
  run 211620: ports 0 and 1 opened, each with its haptic stream, and
    both reported connected
  the owner's own launch from the home screen: the launching user's
    controller became port 0 and the other port 1; both were opened again
    after RetroArch re-initialised input, and a racing game played with
    both controllers
The committed source differs from build 95a82988 only in the monitor's
trace format, which the host test covers; that build was not run on the
console.
Host test: tests/test_input_ps5.py PASS (the four-player scenario: join,
separate input and rumble, sign-out, rejoin, the first player kept, an
open failure, a full house, the monitor, re-announcement after a reset).
Command:
  tools/run-title.sh --no-build --no-deploy --pad-monitor --watch 120
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 21:26:17 -04:00
Mihawk 26c003b61a Game mode: every frontend starts its games in RetroArch the same way
A frontend never runs a game itself. It asks the title to run the game in
RetroArch, in a process of its own, and to come back to it afterwards.
src/ps5_game.h and src/ps5_game.c are that contract, compiled into
eboot.bin and into every frontend executable (tools/build-frontend.sh),
so all frontends share one implementation:

- The frontend writes /app0/game-request.txt (content, core, its own
  executable, a state string) and restarts the title as eboot.bin
  --ps5-mode=game. Its launch command can simply be RetroArch's own,
  "/app0/eboot.bin -L <core> <content>"; ps5_game_parse_command reads
  it, shell escapes included.
- eboot.bin (src/frontend_mode_ps5.cpp) takes and checks the request.
  The core is the one RetroArch's playlists associate with the content
  when they name one of the title's cores, else the frontend's. A
  request that can't run is refused back to the frontend with the
  reason. RetroArch starts on the game (-L, no --menu,
  quit_on_close_content = CLI from config/game-mode.cfg). Once it has
  quit, /app0/game-result.txt gets the status and seconds, and the
  title restarts as the frontend.
- ES-DE: its launch (patch, FileData::launchGame) saves its game lists,
  releases the display and calls the contract. Its start (patch,
  ViewController::goToStart) counts the play, adds the play time and
  opens the system's game list on the game. systems.tsv gives each
  system a default core from the title's cores.
- The capture hook's "launch" action and tools/run-title.sh
  --frontend-launch start a game unattended.

Evidence: evidence/game-mode/ (capture.json, expectation.json,
capture-test.jsonl, gamelist-snes.xml); base PS5 13.40: es-de, eboot
(Donkey Kong Country 2 with snes9x, SRAM saved to
savefiles/Snes9x), es-de back on the game with playcount 1 and
playtime 11; no fatal signal.
Command:
  PS5_FRONTENDS='es-de picker' tools/build-title.sh
  tools/run-title.sh --no-build --relaunch-test=1 \
    --relaunch-image=es-de/es-de.bin --frontend-capture=4,20 \
    --frontend-launch --retroarch-frames=600 --watch 75
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 18:09:40 -04:00
Mihawk 8cb7e980bf Open the title on a frontend picker: RetroArch or EmulationStation
A launch from the home screen now shows a pre-screen in
PS5_VulkanTemplate's Gloss theme with two cards, each with a preview
captured on the console: RetroArch's XMB and ES-DE's Alekfull NX SNES
view. Choosing one restarts the title as that frontend (approach B,
LoadExec). Quitting either one comes back to the picker, and CIRCLE
in the picker closes the title.

- frontends/picker/picker.cpp: the picker, a program of the template's
  UI module. tools/build-picker.sh builds it the template's way (a
  generated one-program title at the pinned template commit, with its
  app root moved to /app0/picker) and stages picker/picker.bin, the
  kit's assets and the previews (assets/picker, NOTICE.md credits them).
- src/frontend_mode_ps5.cpp: eboot.bin decides first. --ps5-mode=
  retroarch runs RetroArch, es-de starts ES-DE, and no mode starts the
  picker, except for a test run. RetroArch the picker started goes
  back to the picker when it quits.
- tools/run-title.sh writes /app0/test-run.txt before every launch (as
  src/main.cpp documents), so scripted runs keep starting RetroArch;
  --picker-test=FRAMES:CHOICE, --retroarch-frames, --frontend-quit.

Evidence: evidence/frontend-picker/ (capture.json, expectation.json,
picker-test-es-de.jsonl, picker-test-retroarch.jsonl); base PS5 13.40:
eboot, picker, es-de, eboot, picker (ES-DE quit) and eboot, picker,
eboot (RetroArch, 600 frames), eboot, picker, with no fatal signal.
Command:
  PS5_FRONTENDS='es-de picker' tools/build-title.sh
  tools/run-title.sh --no-build --picker-test=300:es-de \
    --frontend-capture=15 --frontend-quit --watch 60
  tools/run-title.sh --no-build --picker-test=300:retroarch \
    --retroarch-frames=600 --watch 60
Gates: tools/verify.sh PASS (format unit build integration evidence).
2026-10-04 17:37:33 -04:00
Mihawk d200efa4c6 Prove the driver's display sizes on the console with a display modes test
The Vulkan driver's display (RADV's VideoOut WSI, PS5_Mesa dc82d01, pinned by
PS5_Vulkan ab37acd) now offers 3840x2160, 2560x1440 and 1920x1080 instead of
4K alone. src/display_modes_ps5.cpp, armed by /app0/display-modes-test.txt
(tools/run-title.sh --display-modes-test[=frames]), makes a device on the
title's driver before RetroArch does and presents every mode in turn, then the
first again, each with a pattern a person can judge: two shades of one colour a
size split at the middle and a white border on every edge. Each mode's result
is a line of /app0/display-modes-test.jsonl; RetroArch then starts as usual.
RetroArch's default (the largest mode) is unchanged; video_fullscreen_x/y
selects a smaller one.

Verified:
  TMPDIR=build/tmp bash tools/verify.sh -> PASS (format unit build integration
    evidence), building against PS5_Vulkan's archive at dc82d01 (build
    8128ea84...); the host test also ran armed against a host build of the
    WSI (PS5_WSI_MODES_ICD): every mode presented.
  tools/run-title.sh --no-build --display-modes-test=180 --watch 60 on the
    base PS5 (13.40, 1080p screen), build ce576f3d (same driver revision):
    sets 0-2 registered (buffers 0-14), 180 frames each in 2.96-3.00 s,
    3840x2160 again from set 0, PASS. The owner saw each size fill the TV,
    border on all four edges and split centred, and RetroArch steady after.
  A first run (PS5_Mesa 3321f8f) also offered 1280x720: VideoOut refused its
    set at buffers 15-19 (0x80290001) and RetroArch flickered after it, not
    alone; the size was left out of the merged driver.
Evidence: evidence/display-modes/ (python3 tools/evidence.py compare)
2026-10-04 14:22:07 -04:00
Mihawk d8cd370ce2 Prove the frontend handover's title restart on the console
The frontend picker hands over by restarting the title in a new process
(approach B). src/relaunch_ps5.cpp measures that restart: armed by
/app0/relaunch-test.txt (tools/run-title.sh --relaunch-test[=N]), each process
records its generation, argv, flexible memory, pid and clock in
/app0/relaunch-test.jsonl, restarts the title through
sceSystemServiceLoadExec("/app0/eboot.bin", {"--ps5-relaunch=N", NULL}), and
the last one continues into RetroArch. main() now takes the process arguments.

Found on the console: LoadExec's arguments become the new process's whole
argv, with no program name in front (argc=1, argv[0]="--ps5-relaunch=1"); a
home-screen launch gets argc=1, argv[0]="". The first run (build f935ae4e)
read from argv[1] and failed its argument check; the parser now reads from
argv[0] and the host test feeds argv in the console's shape.

Verified:
  TMPDIR=build/tmp bash tools/verify.sh -> PASS (format unit build
    integration evidence); build identity 453864d6...
  tools/run-title.sh --no-build --relaunch-test=5 --watch 60 on the base
    PS5 (13.40): 5 restarts, pids 117-122, each with its arguments,
    419430400 bytes flexible free at every start, 0.56-0.61 s per restart;
    kernel log EXEC x6, "Kill for LoadExec => 0" x5, no fatal signal;
    RetroArch started after the chain with XMB assets loaded.
Evidence: evidence/loadexec-relaunch/ (python3 tools/evidence.py compare)
2026-10-04 13:34:42 -04:00
Mihawk 09ea2c2a66 Add verified console updates and BIOS alerts to the WebUI
Download and verify published packages on-console, stage changed managed files, preserve user data, and install after frontend shutdown. Set eboot execute permission explicitly so native installations relaunch.

Validation: tools/verify.sh (118 tests, native build and all gates); browser state checks; actual Alpha 6 download/install/relaunch and unchanged config. Evidence: evidence/webui-update/.
2026-10-02 19:06:46 -04:00
Mihawk aed9543a76 Add native RetroArch WebUI on port 6769
Serve the approved purple layout with local assets, streamed content transfers, release notes and next-launch settings. Keep the service within the title lifetime and preserve explicit launch overrides.

Verify: CCACHE_DIR=build/verification/ccache BUILD_JOBS=8 bash tools/verify.sh (all five gates; 92 tests), real browser integration including throttled keyboard cancellation, and two native console launches. Evidence: evidence/webui/{capture,expectation}.json; replay with python3 tools/evidence.py compare evidence/.

Design review and normal Impeccable completion passed in a hash-verified identical-source snapshot because the original-root fingerprint scanner failed; records remain in build/verification. No game performance soak claimed.
2026-10-02 11:07:52 -04:00
Mihawk 38284d1cdc Recover PPSSPP framebuffer OOM and track shared memory pressure
Use SDK f674976 for blocking heap contention and live direct-memory availability. Trim unused PPSSPP caches under pressure, drain retired GPU objects and retry framebuffer allocation once; close content on unrecoverable failure. Report CPU/GPU/free/largest memory around state loads and failures.

Verified: all five tools/verify.sh gates, 87 tests including 108 injected GPU failures, all 16 core builds; SDK 318 checks plus memory scanner tests. Console evidence: evidence/ppsspp-memory-recovery. Balanced and 6x/8x pass repeated state round trips; prior 10x/8x crash now recovers first load, then safely closes content after device OOM on second load. Build 8b635e9b installed; user settings/state unchanged.
2026-10-02 08:35:58 -04:00
Mihawk 5f1e1a8439 Title: /app0/radv-threaded.txt turns on RADV's threaded recording
For A/B runs: it sets RADV_THREADED_RECORDING before RetroArch makes its
Vulkan instance.
2026-09-30 03:03:08 -04:00
Mihawk b816c2bb48 Platform probe: "topology" runs the SDK's CPU topology test
The title's thread layout for RPCS3 was chosen from it.
2026-09-30 02:01:45 -04:00
Mihawk d11904b04b RPCS3: GTA IV at 50 fps at 4K from its save state; fast installs; its frame-rate patch
The fork's pin carries GTA IV 1.00's frame-rate patch (its render thread's
frame lock, which RPCS3's database only unlocks for 1.08), savestates that
resume a disc game kept in a dev_hdd0 folder and load over one another, and
files in /app0 written through the console's FTP server once the title's write
budget is spent (the SDK fork's offload streams: GTA IV reinstalled 1414 MiB in
4 minutes with the budget spent, byte for byte). From the baseline state at
300%: 50.4-51.5 fps where the game held itself to 30 (docs/RPCS3_PORT.md, GTA
IV; docs/PHASE_LOG.md).

The platform probe's "offload" word measures writing through that server
from the title. The sampler bounds its frame walk by each thread's stack, which
faulted with every core thread sampled, and reports each busy thread, which
the most frequent groups hid.
2026-09-29 12:50:45 -04:00
Mihawk 7446ade44b RPCS3: the game patch database with frame-rate patches on; write route probe
The title stages RPCS3's game patch database (the fork's bin/patches) in
system/RPCS3/patches, and the core turns each game's frame-rate patch on when
content loads ("Frame-rate patches", on by default; docs/RPCS3_PORT.md).

The platform probe's "routes" word times 1 GiB written with write() and
through a shared mapping, in /app0 and in the folder by its own path: which
route or path the title's writes are held back on after their burst.

The test pad script can push a stick all the way (LS_ and RS_ with UP, DOWN,
LEFT or RIGHT), for runs that walk a game's character somewhere.
2026-09-29 08:15:17 -04:00
Mihawk 19ae1659d2 RPCS3: a loading screen while content installs; Inter staged; SDK c769422
The fork (78dfa8f) installs the firmware and a package on a worker thread while
the core shows a loading screen, until RPCS3's first frame, and takes the
resolution scale as a core option (300% by default). build-rpcs3.sh fetches
Inter 4.1, pinned by digest, and the title stages it with its licence in
system/RPCS3/fonts.

The platform probe's "writes" word runs the SDK's sustained write test (SDK
c769422): a title writes at full speed for a burst of a few GiB, then at about
2 MiB/s, which is why God of War HD's 6.3 GB package installs in half an hour
(docs/RPCS3_PORT.md).
2026-09-28 23:03:23 -04:00
MihawkandClaude Opus 5.5 2afaaecf21 The title's own threads ask for 256 KiB; the release's stability checks
The log flusher, audio worker, permission repair, sampler and core-thread
factory were created with no attributes, which is 64 KiB of stack on this
console; they ask for 256 KiB (src/title_threads.hpp). The release candidate
ran every core through boot, menu and a Quick Menu action, four with threaded
video, and PPSSPP for ten minutes with 25 menu cycles: no crash.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 11:26:34 -04:00
MihawkandClaude Opus 5.5 d466c3f0ae A tester's trace: frontend threads get 2 MiB, 0019's list on the heap
A tester's build crashed re-creating the video driver after content closed:
vk_enumerate_instance_extension_properties read its count 66 KB above the
stack pointer, unmapped. RetroArch creates its own threads with no stack size,
which is 64 KiB here (the payload SDK fork's thread probe; the main thread has
2 MiB), and with threaded video the driver is created on one. This build with
0096 withdrawn died at its first threaded video init, a write fault one page
below the thread's stack in vulkan_context_create_instance_wrapper.

0095 moves 0019's 66,560-byte extension list to the heap and frees the list it
replaces; 0096 gives RetroArch's threads 2 MiB. The payload SDK pin moves to
a110320 (the thread probe, word "threads"). The unit gate's patch count moves
203 -> 212: 0094's seven blocks, missing from its commit's count, and 0095 and
0096; 0019's old block is withdrawn for 0095's. The same trace's half speed
with V-Sync on and its PPSSPP crashes are ../PS5_Vulkan R93's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 10:05:33 -04:00
MihawkandClaude Opus 5.5 a7cd520d46 Patch 0094: save states written without stdio, and the file probe
This console's fwrite() runs at 3-13 MiB/s, where write() of a megabyte or
more runs at 150-230 MiB/s (the SDK fork's file probe). A save state now goes
to the raw descriptor through the frequent-access hint: uncompressed in 4 MiB
chunks, compressed in 1 MiB ones. An LRPS2 state of 50.6 MB saves in 0.28 s
uncompressed (2.8 s before) and 1.8 s compressed (2.3 s). Small writers keep
stdio.

The title pins the SDK fork at 66f658e and its platform probe takes "files".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 08:35:30 -04:00
MihawkandClaude Opus 5.5 5327e4832a Build with my payload SDK fork, and adopt its platform layer
The title and its cores build with ../PS5_PayloadSDK at a pinned
revision (tools/setup-native-dependencies.sh): the v0.42 release with
the fork's headers and platform layer installed over it. The builder
links SDK archives by name (APP_SDK_ARCHIVES); the core stamps include
the fork's revision.

- The machine context: the fork's sys/_ucontext.h is the console's
  layout, so the crash reporter, the sampler and the Dolphin, PPSSPP
  and LRPS2 ports read uc_mcontext's fields; the six-word offset each
  carried is gone.
- The libc gaps: src/ps5_directory.cpp and most of src/libc_shims.c are
  the platform's ps5_* functions; src/platform_wraps.c binds the
  title's --wrap links to them and tools/core-imports.py a core's
  imports. The directory fixture test moved to the fork.
- Executable code and guest memory: Dolphin's, PPSSPP's and LRPS2's JIT
  code is the platform's executable direct memory near each core, at
  upstream cache sizes (Dolphin 128 + 64 MiB, LRPS2 305 MiB), and their
  arenas are the platform's direct-memory objects, views and ranges.
- A profiled run reports the platform's live counters after its memory
  line; the platform probe test aid gains the huge and full tests.
- docs/PLATFORM_FIRMWARE_ANALYSIS.md: the 10.01 modules' export tables
  against the SDK, and where the platform layer lives.
- tools/run_clang_tidy.sh tidies each C++ test with the flags its
  harness builds it with (the app-source pass still lacks the build's
  include paths; a separate task).

Console (docs/PHASE_LOG.md): Dolphin Profiles 0, 1 and 9 and Rogue
Leader, PPSSPP God of War and LRPS2's BIOS run with no crash; Dolphin
has 58 MiB more flexible memory in game and LRPS2 160 MiB more, with
the caches at upstream sizes; the platform's counters return to zero
when content closes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 01:02:30 -04:00
MihawkandClaude Opus 5.5 d89c5a6f55 The title's folders and files are reachable over FTP
FTP runs as another user than the title, and RetroArch creates its
folders 0750 and some files with mode 0, so savestates/dolphin-emu
answered FTP with "550 Permission denied". mkdir, open and fopen are
wrapped at link time -- a core's imports bind to the same wrappers --
and give what they create 0777 (folders) or at least 0666 (files). A
thread started first in main gives everything under /app0 the bits it
lacks, which repairs what earlier builds made; only modes change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 09:03:04 -04:00
MihawkandClaude Opus 5.5 9514d7ada9 Test aid: a test run copies one file into its own directory
Profile 10 stresses save states in a directory of its own, so the entry
state has to be there too, and the FTP account could not read mine.
/app0/state-copy.txt names a source and a destination; a test run
copies the one to the other before RetroArch starts. It never replaces
a file and never writes under /app0/savestates or /app0/savefiles, and
the file is swept with the other test files on a launch that is not a
test run.

The memory report's declarations had separated the terminate handler's
comment from its function; they sit above it again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 09:02:53 -04:00
MihawkandClaude Opus 5.5 cc75fc1353 Profiles 3-7 on the three games; a profiled run reports flexible memory
PHASE_LOG records Profiles 3 to 7: torture, GPU and RAM EFB copies and
the 1x-6x ladder at full speed on RE4, Melee and Wind Waker; MSAA after
../PS5_Vulkan R75-R78 (2x, 4x and 8x at full speed, the maximum torture
correct and GPU-bound).

A profiled test run (the driver's /app0/ps5vk-profile.txt survived the
stale test file sweep) prints the flexible memory left every ten
seconds from the log flusher, beside the driver's direct_live, so a
soak's leak shows as a line that only moves one way. verify.sh: all
gates pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 06:28:27 -04:00
MihawkandClaude Opus 5.5 5c5f20d46e Dolphin: Wind Waker's 3D scene correct after driver R64/R65; bisect aids
Wind Waker drew its 3D scenes as a corrupt near-camera surface, then (after the
first fix) thin triangles to the screen corner and a minimap spill. Both were
primitive-restart faults in ../PS5_Vulkan: R64 (34ca3ad, a bare restart write
after each draw landed mid-draw) and R65 (75f33eb, every submission a copy
splits off starts with restart off). Found with a console FIFO log played by
the core and by desktop Dolphin from the same tree, bisected by object range.

Evidence (evidence/dolphin-restart-strips, raw klog/dolrestart-evidence.txt):
the FIFO log's screenshots against desktop Dolphin, mean difference per channel
64-71 before, 1.23-1.53 after R64, 1.13-1.16 after R65 (resampling); my save
state on Outset Island (--entryslot=0, 3600 frames) loads, draws cleanly and
exits with rarch_main 0 and audio errors=0.

Core patch (patches/dolphin/ps5-port.patch, regenerated from the tree):
- Core/Core.cpp: single-core FIFO playback returns to retro_run with the FIFO
  CPU core injected, as CpuThread does; running CPU::Run() there never
  returned in single-core libretro mode (.dff playback hung).
- debug mode "objects A B" plays only objects A-B of each FIFO frame (debug
  file only; $FIFO_OBJECTS on the host).
- the temporary host A/B hooks (depth clamp, draw log, restart) are gone.

Title: the stale-test-file list covers /app0/dolphin-debug.txt and
/app0/ps5vk-shader-cache-dir.txt (a previous run left the latter on the
console, redirecting the driver's shader cache; removed).

tools/verify.sh PASS (format unit build integration evidence), 40 captures.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 20:38:57 -04:00
MihawkandClaude Opus 5.5 211bfef3a1 Dolphin core: Wind Waker boots, JIT64 + fastmem; save states work
libretro/dolphin c6630001e0 (Dolphin 2609) cross-builds with
tools/build-dolphin.sh and patches/dolphin/ps5-port.patch and ships in the
title. Platform work in the core patch: guest RAM in direct memory mapped at
every mirror, the fastmem arena as a kernel range reservation away from the
GPU window, JIT code mapped RW then RWX at 0x3_0000_0000, the console's
shifted mcontext and SIGBUS in the fault handler, a 32 MiB code cache,
test-only /app0/dolphin-options.txt overrides, and no false "Failed to load
Vulkan library" alert. tooling/dolphin/ps5-libc-shims.cpp supplies the libc
entry points the console lacks.

Title: openat/fdopendir/unlinkat/fchmodat and libc's opendir family
implemented or rerouted for the title's libc++ (openat resolved to 0 in
std::filesystem::remove_all); utimensat over utimes; small allocations go to
direct memory first and a refused libc realloc moves the block there (the
driver's compiler and a strdup at exit both failed on an exhausted libc heap).
Frontend patches: 0089 enables VK_KHR_get_physical_device_properties2 on the
instance (Dolphin's VMA); 0090 keeps the synchronous readback inside the
caller's viewport (save-state thumbnail overran ~1 MB and crashed).

Evidence: evidence/dolphin-wind-waker-boot (dol12: 1800 frames, zero driver
refusals, zero failed Vulkan calls, audio errors=0, clean exit; the title
screen's mountain is missing and open) and evidence/dolphin-save-states
(dolss3 save and dolld2 --entryslot=0 load, clean exits; dolss1/dolld1 were
the crashes). tools/verify.sh: PASS (format unit build integration evidence;
patch count 199), 39 captures replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 12:56:34 -04:00
MihawkandClaude Opus 5.5 df15fcb6b0 Stop logging from stalling frames; test files last one launch; sampler
Loading a God of War save state froze the picture for 21.5 s, and gameplay
stuttered. A sampling profiler (below) put the frame thread's stall time in
fprintf, fputs and vfprintf: every log line was its own write to the
console's storage on the thread that logged it.

- The trace file (stderr) is buffered, and a flusher thread writes every
  output stream out four times a second. The crash handler flushes stderr
  first when the crashing thread does not hold it (ftrylockfile), and the
  terminate handler flushes before aborting.
- Port patch 0088: RetroArch's log gets a 256 KiB buffer and no longer
  flushes after every message (it stacks on 0087, keeping its marker).
- Test files belong to one launch: the harness writes /app0/test-run.txt
  just before starting the title, which consumes it; a launch without it
  deletes stale test files (args.txt, flags) before anything reads them.
  A killed test run had left args.txt behind, so the maintainer's own
  launches went straight into a test game that quit itself. Proven on the
  console: a stale args.txt was removed ("stale test files removed = 1").
- src/sampler_ps5.cpp, opt-in (/app0/ps5-sampler.txt): samples the main
  thread and named core threads every 2 ms by signal and reports, per ten
  seconds, where they were while no frame had been presented for 50 ms,
  with example stacks. It reads ../PS5_Vulkan's new
  ps5vk_debug_last_present_ns. The core thread factory registers threads.

State load, same save state (klog): 21.5 s with the driver's diagnostic
logging left on the console, 456 ms without it (samp6), 124 ms with the
trace buffered (buf1), 61 ms with RetroArch's log buffered too (buf3) --
one frame, the load itself, and audio full right after.

Verified: tools/verify.sh PASS (format unit build integration evidence).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 08:18:20 -04:00
MihawkandClaude Opus 5.5 91642cb6e3 Retry core thread creation on EAGAIN; log terminate detail and audio windows
About one PPSSPP launch in three died at startup with "thread constructor
failed: Resource temporarily unavailable" (EAGAIN, code 35): the core's
thread pool starts while the frontend compiles its first shaders, and the
title's small flexible-memory budget was momentarily held (the Vulkan
driver's 32 MiB compile stack among its users). The core thread factory now
retries a refused pthread_create for up to two seconds before passing the
error on.

The terminate handler reads the thrown object through
__cxa_current_primary_exception, so a std::system_error names its what()
and error code, and the standard exception types their what(); that is what
identified the failure above.

The audio driver prints one line per ten seconds of AudioOut's own clock:
the frames the core delivered and the silence filled in. It is the direct
measure of whether emulation keeps real time: God of War: Ghost of Sparta
at 10x went from ~420,000 of 480,000 frames a window to 480,000 with no
silence once the driver's presentation became a FIFO queue (klog pace1 vs
pace2 of 2026-09-24).

Verified: tools/verify.sh PASS (format unit build integration evidence).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 04:26:42 -04:00
MihawkandClaude Opus 5.5 564d5555e4 Rebuild PPSSPP from v1.20.4 on the Vulkan renderer: God of War boots
The core is rebuilt from the v1.20.4 release as one patch
(patches/ppsspp/ps5-port.patch; tools/build-ppsspp.sh, PPSSPP_DEV=1 builds
the tree as it stands). Vulkan through the frontend's device (no GL, no
GLEW), the x86-64 JIT, and FFmpeg 3.0.2 cross-built from the tree's own
submodule for video. In the core: executable memory is mapped read-write
then made executable (the console's working order), guest memory is an
anonymous shared object mapped into a 4 GiB reserved range at
0x6_0000_0000 (outside the GPU's window at high word 2), the fault
handler reads the console's machine context six words past the SDK
header's, and the libretro surface path is VK_KHR_display.

In the title, what a core needs that the console did not give it:
- core thread creation and thread-specific data go through title frames
  (src/core_threads_ps5.cpp): libkernel resolves the caller to a module
  and faults on the core's anonymous mapping. Core threads get a 2 MiB
  minimum stack (glslang's parser overflowed the default).
- a core allocates from an overflow heap in direct memory first
  (src/overflow_heap.c, dlmalloc 2.8.6 MIT, 32-byte aligned as the
  target's default new alignment): PPSSPP filled libc's small heap, after
  which libkernel's own condition variables and sceAgcInit failed.
- gmtime_r and arc4random shims (src/libc_shims.c).
- a crash report in trace.txt (rip, rsp, return address, stack words).
- patch 0087: the log file is line-buffered, so a fault keeps its lines.

Console: GoW boots, loads, plays its intro video and menu and renders its
real-time intro cutscene correctly at 60 FPS content; the menu's
background still renders wrong (driver depth sampling is the lead).
Driver ../PS5_Vulkan 8d61168. verify.sh PASS (patch count 193 -> 194).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 22:52:08 -04:00
MihawkandClaude Opus 5.5 6a47e3e551 Keep the last frame on screen across video reinits; recheck every core; fix FBNeo's screenshot
The black half-second on menu open/close, content close/load and video
reinits was the driver closing VideoOut with each swapchain and switching
the output 120 -> 60 -> 120 Hz. main.cpp now retains VideoOut
(../PS5_Vulkan 49679c9, ps5vk_display_retain) and releases it on quit.
Measured with a pad script (evidence/display-retention): menu handovers
7 ms instead of 297-344 ms, close content 280 ms and History 437 ms with
the previous image on screen instead of a blank panel and a mode switch;
0 black presents; quit restores the default mode.
/app0/ps5vk-no-retain.txt restores the old behaviour for comparison.

Every core rechecked at 119.88 Hz on the current driver
(evidence/core-recheck-current-driver): FCEUmm, Snes9x, mGBA (GBA .7z,
GB), FBNeo, Genesis Plus GX (MD, SMS, GG); 1,200 frames, exit
screenshot colours checked, audio errors=0, status 0.

FBNeo's screenshot crashed on a null call. Patch 0086: the scaler
allocated ~97 MB of intermediate frames a same-size conversion never
reads, failed beside FBNeo's 170 MB core, and the screenshot called an
unset converter. They are now allocated only for scaling, and a
conversion that cannot be set up fails the screenshot. Patch count
188 -> 193 (0086 is five edits).

Test aids: /app0/pad-script.txt (timed button presses), a crash report
in trace.txt (rip, rsp, return address, stack words; the console's
mcontext has rip at word 26 and rsp at 29) and the core base in the
loader's ready line, which together symbolised the FBNeo crash.

tools/verify.sh PASS (5 gates), 37 captures replay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 21:08:02 -04:00
MihawkandClaude Opus 5.5 bfc2bf9b55 Present at 120 Hz by default, fall back to 60 Hz, keep cores at speed
The title declares high-frame-rate output (attribute3 0x80040), so the
current driver offers and selects 3840x2160 at 119.88 Hz. Patch 0084
picks the largest display mode and then the highest refresh; 0085 makes
video_refresh_rate follow the mode the display actually got and turns a
saved swap interval of 1 automatic above 100 Hz, so a 60 FPS core shows
each frame for two vblanks. Where 120 Hz is not offered, the same logic
lands on 59.94 Hz with interval 1. main.cpp drops --menu when args.txt
launches content, so a run can measure a core unattended.

Console: FCEUmm ran 1,800 frames in ~30 s at 119.88 Hz (1,199 presents
per 10 s) and at 59.94 Hz without the metadata (600 per 10 s): correct
speed both ways. Evidence output-120hz, output-60hz-fallback. verify.sh
PASS; patch count 185 -> 188 for 0084's two edits and 0085.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-23 19:39:09 -04:00
Mihawk 1fd4bb2b04 Narrow the PPSSPP worker crash to libkernel's module lookup
PPSSPP dies in ThreadManager::Init on the console, on its first worker thread.
This commit records what the crash is and what it is not, so the next attempt
starts from here.

The console's own dump: SIGSEGV on a worker thread, fault address 0x70, rip
0x8000407fb, backtrace 0x80004055c, 0x800040638, 0x20185ea6a, 0x800074d0.
/system/common/lib/libkernel.sprx is readable over FTP and can now be
symbolized: SharpProspero's NidEncoder documents that a NID is the first eight
bytes of SHA1(name || salt), byte-reversed and base-64-encoded with a custom
alphabet, and it validates against seven documented pairs (puts=YQ0navp+YIc,
malloc=gQX+4GDQjpM, ...). Computing NIDs for the SDK's 4,328 kernel/libc symbols
names 1,111 of the module's 1,270 exports, which turns every console backtrace
inside libkernel into function names.

Naming the frames gives the mechanism. 0x8000407fb is
pthread_get_specificarray_np+0x3b (NID td+DYvbbDfk), reached from the thread
creation path pthread_create_name_np. Disassembling it shows a frame-pointer
walk: take a return address two frames up, look it up in a table of 0x98-byte
range records, then read [result+0x70] with no null check - rbx in the register
dump is 0x8000711d0, libkernel's __stack_chk_guard, which confirms the reading.
The address that could not be resolved, 0x20185ea6a, is the third backtrace
frame: a return address inside this title's core, which the loader mapped
anonymously. The core is not a registered module, so the lookup misses and the
dereference faults.

src/thread_probe.cpp is the opt-in diagnostic (/app0/thread-test.txt) that
tested every case buildable in the title - 32 concurrent std::threads,
thread_local in each, a heap std::mutex and std::condition_variable used by 1 and
32 threads, a thread entered on an anonymous page, a thread entered on a core
export, a thread calling core code, a libkernel call whose immediate caller is an
anonymous page, and pthread_getspecific from an anonymous page. All of them pass
({"stage":"done","created":32,"ran":32,"joined":32,"tls_ok":32} and successors).
PPSSPP still dies at the same instruction, so the trigger is not any of those
alone.

patches/ppsspp/0005-ps5-thread-name.patch stands on its own: PS5 defines
__FreeBSD__, so PPSSPP took its BSD branch and every worker called
pthread_set_name_np, which no shipped core had ever used.
patches/ppsspp/0006-diagnose-thread-pool.patch is the temporary instrumentation
that named the failing step ("creating 0", "created 0", then death).

Gates: bash tools/verify.sh format unit - PASS, 74 tests.

Next: remove PPSSPP's thread_local uses (the plan's A2 step, now motivated by the
emutls path being exactly the family in the backtrace), or make libkernel's
lookup succeed for core addresses.
2026-09-20 09:26:01 -04:00
Mihawk 481c675e0d Add opt-in XMB allocation diagnostics for manual console testing
Keep native/mapped allocation policy intact; observe aligned Vulkan host allocations and texture/queue-idle lifetimes with allocation-free failure logging and periodic summaries. Snapshot driver archives locally for an attributable diagnostic link.

Verified: PS5_MEMORY_DIAGNOSTICS=1 bash tools/verify.sh; final bash tools/verify.sh format unit (68 tests); python3 tools/check-memory-diagnostics.py. Evidence: evidence/xmb-memory-diagnostic/{capture,expectation,inspection}.json. Console validation pending owner intervention; no upload or launch and no crash fix claimed.
2026-09-19 18:30:27 -04:00
Mihawk d2a91b395b Port native mGBA and fix core/menu lifecycle rendering
Build pinned mGBA with this PS5 SDK, official metadata and both GB/GBA engines.
Support validated C initializer arrays, native directory/time imports and an
explicit config path. Map large title/core allocations so GBA archives load.
Correct mGBA callback colours and cached frame ownership, crop padded core
textures during presentation, and use the native shell exit after cleanup.

Verified: bash tools/verify.sh (format, unit, build, integration, evidence;
58 tests), then bash tools/run-title.sh --no-build --core-test=mgba --watch 180.
Owner confirms GB/GBC/GBA loading, correct colours/native Quit, and clean menu
and next game. Final capture has zero Vulkan refusals, GPU failure records or
kernel fatal-signal reports; normal frontend exit occurred before window end.

Evidence: evidence/mgba-native/{capture,expectation,iterations,build,abi}.json,
loader/recovery reports and exact linked-driver hashes. Replay with
bash tools/verify.sh evidence. Final build identity:
82024b89e74bbad4ad2ce2e2916d1a49baf26ac325fef20fc71a2c168b862337.

Patch count is deliberately 139: archive diagnostics, menu/cache ownership and
padded-source sampling edits. PS5_Vulkan was not modified. Saves/states,
long-run timing and a fresh FCEUmm/XMB transition matrix remain unverified.
2026-09-19 16:00:01 -04:00
Mihawk 63a440414a Load native FCEUmm cores safely and present software core frames
Replace payload dlfcn hooks with a bounded ELF loader and explicit native
runtime bindings. Separate core RX/R/RW segments, reject unsupported ELF
features, and release failed loads. Guard failed menu selection before
frontend teardown and stop polling drivers after failed initialization.

Read core files through mapped buffers and bounded POSIX reads. Convert
libretro XRGB8888 frames to matching RGBA8 staging/sampled textures so real
content uses the verified Vulkan copy path rather than the RGB565 compute
branch. Keep video_ps5 selectable and preserve frontend/audio/error logs.

Validation: tools/verify.sh passed all five gates (52 tests). Console command:
tools/run-title.sh --no-build --core-test --watch 180, with manual core/game
selection. Eight ELF load/unload cycles and live-menu failure recovery passed;
owner confirmed flawless gameplay. Zero GPU refusals/API failure records and
kernel fatal signals across captured launches. Return-to-menu shortcut and
repeated game unload/reload remain unverified; owner closed/reopened the app.

Evidence: evidence/native-core-loading/{capture,expectation,loader,recovery,
abi,iterations}.json; replay with tools/verify.sh evidence. Accepted title
identity 9b287ca7e0d4a04721c68d30fb88b678a62cc568c1f2d44b75716b464c21b6d5.
No PS5_Vulkan edits by this task; its independently advancing checkout is
not used as a substitute for the accepted title's archive-bound identity.
2026-09-19 14:47:09 -04:00
Mihawk ab55775550 Fix PS5 configuration persistence and directory browsing
Register a native platform frontend to preserve startup argv and supply browser roots and directory defaults. Keep live settings separate from the packaged seed. Supply the known executable path to avoid the procfs-related config-save crash, and enumerate directories through SDK getdents with a 64 KiB buffer.

Validation: tools/verify.sh passes all five gates (35 unit tests, 15 evidence records). tools/run-title.sh --no-build --watch 90 lists 96 /app0 entries with zero errors, stays alive, and is script-closed with zero Vulkan refusals/API failures. Owner confirms visible folders and configuration files. Live config is unchanged across upload/restart.

Evidence: evidence/native-paths/{capture,expectation}.json includes failed diagnostics and final acceptance. Build identity 26139a294d687ccf21c8fa779e5ad3883273b873b71ce67e1df48f48589f8f76. Patch count 102 to 105; fresh replay/idempotence verified. Runner snapshots build identity to avoid false stale-log failures during subsequent builds. PS5_Vulkan unchanged.
2026-09-19 13:08:24 -04:00
Mihawk 1b849dac1d Add native PS5 PCM audio driver with verified buffering
Register audio_ps5 and select it by default. Feed native AudioOut through a bounded worker queue with byte-based writes, rate negotiation, backpressure, pause/resume and cleanup. No SDL or Opus dependency.

Validation: tools/verify.sh passes all five gates (32 unit tests, 14 evidence records). tools/run-title.sh --no-build --audio-test --watch 45 records 193536 accepted/played frames, zero errors/discards, correct channel tones confirmed by the owner. A normal --no-deploy --watch 45 run remains alive and is script-closed with zero Vulkan refusals/API failures.

Evidence: evidence/native-audio/{capture,audio-test,expectation}.json. Build identity 801df0ac6a5754c3e6a6ea688f1e49e8ddd2041aeb131a637b8c8b59f4030d55. Patch count increases from 100 to 102 for registration and default; fresh replay/idempotence verified. PS5_Vulkan unchanged.
2026-09-19 12:40:01 -04:00
Mihawk 62d0a4747d Keep development logs while buffering GPU timing off the frame loop
Retain frontend INFO/WARN/ERROR, driver errors, startup trace and klog.
Restore frontend log setup after rebuilt arguments, mark its build identity,
and retrieve it with each run. Remove periodic frame and button chatter;
log menu texture handover once. Profiling is opt-in, bounded and written only
after capture; validate per-frame partitions and presentation-return cadence.

Verified: bash tools/verify.sh (all gates, 28 tests); fresh vendor patch
replay/idempotence (86 edits). Two 60-second captures completed: first at
59.940238 FPS with maximum interval 16.905813 ms; fresh frontend logging
exposed three late texture-probe stalls, then those probes were limited.
Final refined build launched with zero refusals, logged handover once and
returned 0 before profiling completed; no final timing claim is made.
User requested ending performance investigation and proceeding to XMB.

Evidence: evidence/vulkan-buffered-logging/{capture,expectation}.json
Replay: python3 tools/evidence.py compare evidence/
Console: bash tools/run-title.sh --no-build --gpu-profile 60 --watch 80
Analysis: python3 tools/analyze-gpu-profile.py klog/gpu-profile-<stamp>.tsv
2026-09-19 11:30:05 -04:00
Mihawk 574974ee2e Verify the running title using an input-derived build identity
Two regressions failed when generic startup strings accepted an older executable. Require the unique embedded identity on FTP readback and log it at startup; keep the generated header ignored.

Verify: bash tools/verify.sh (all five gates, 25 tests with pending colour work); bash tools/run-title.sh --no-build --watch 30. Evidence: evidence/vulkan-build-identity/{capture,expectation}.json records matching staged and running identities. Pixel correctness is not claimed.
2026-09-19 10:14:33 -04:00
Mihawk 7461171cbc Dismiss the title splash before starting the Vulkan frontend
Verify: bash tools/verify.sh (all five gates); bash tools/run-title.sh --no-build --watch 90. Evidence: evidence/vulkan-splash-dismissal/{capture,expectation}.json, replayed by tools/verify.sh evidence.

The public splash call returns zero and the owner confirms the Vulkan menu is visible. Blue colours and flickering black triangles remain; the owner manually closed the run, so full-window acceptance is not claimed. CPU video and PS5_Vulkan stay unchanged.
2026-09-19 10:02:19 -04:00
Mihawk 979141e27a capture: the trigger works on the console, the driver's readback does not
Command: bash tools/build-title.sh && (stage /app0/args.txt:
"--ps5-capture=90 --ps5-capture-path=/app0/shot.png") && bash tools/run-title.sh
--no-build --watch 20
Evidence: /app0/trace.txt (klog/run-PPSA99169-031642.log) contains
"capture: frame 90 of 90, take_screenshot -> failed (/app0/shot.png)" - the port's own
options are read by the patched vulkan_frame, the budget is reached, take_screenshot is
called, and the trace says whether it worked. bash tools/verify.sh: PASS (format unit
build integration evidence).

gfx/drivers/vulkan.c (patches/series 0031): the frame counter and the screenshot call,
in vulkan_frame, because that is the one path every frame takes. A second hook in
video_driver_cached_frame (0030) was written and removed: it never ran on the console,
because a content-less run does not take that path either.
src/main.cpp: --ps5-* lines are the port's own and no longer reach RetroArch's option
parser.

The readback behind take_screenshot (vulkan_readback's synchronous path) fails and its
reason goes to /app0/retroarch.log, which never flushes. That, and the picture itself,
are the next step.
2026-09-19 03:21:08 -04:00
Mihawk 49dfd220db port: an unattended argument file, and the frontend's screenshot support compiled in
Command: python3 (stage /app0/args.txt over FTP) then
bash tools/run-title.sh --no-build --watch 20
Evidence: klog/trace-r4.txt contains "argv extras from /app0/args.txt = 3" - the title
read the file and passed three extra arguments to rarch_main; klog/run-shot-r4b.log and
klog/run-PPSA99169-025444.log show the run with HAVE_SCREENSHOTS compiled in ("it ran for
20s and this script closed it"); bash tools/verify.sh format -> PASS (the full gate set
passed in the previous round and was re-run for this step's format fix).

src/main.cpp: /app0/args.txt, one argument per line, is appended to argv when present.
The console's launcher passes no arguments, and RetroArch's unattended capture options
are the ones a run needs to change.
tools/build-retroarch.sh: -DHAVE_SCREENSHOTS, because RetroArch's
--max-frames/--max-frames-ss/--max-frames-ss-path block is #ifdef HAVE_SCREENSHOTS and
was compiled out.

The capture does not fire yet: RUNLOOP_TIME_TO_EXIT compares max_frames against the
core's frame_count, and this title runs with no content, so the counter never advances.
That is the next step, recorded in docs/PHASE_LOG.md.
2026-09-19 03:01:08 -04:00
Mihawk 34d9200ecf Get the Vulkan driver to a created pipeline, a running runloop and a first frame
The console run now reaches a frame. In order: video_vulkan selected, the console's
khr_display WSI, a device, a swapchain at 3840x2160, four textures, a vertex buffer,
the stock shader reflected, both stages compiled by the driver's own compiler,
vkCreateGraphicsPipelines returning 0, vulkan_init handing back a live pointer, the
input driver opening the pad, and runloop_iterate reaching vulkan_frame -> vkQueueSubmit.
Nothing is on screen yet: the first frame's command buffer already has a render pass
open when the backbuffer pass begins, and Mesa's common CmdBeginRenderPass2 asserts.

Three of the four fixes are port patches, all of them requests that driver refuses:

  0016  its pipeline check accepts only VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, and its
        draw path refuses a non-indexed draw whose first vertex is not zero; the two
        quads are now six-vertex lists, the second triangle reached through the
        binding's own offset. This is what turned VK_ERROR_UNKNOWN into a pipeline.
  0017  it refuses any sampler that is not clamp-to-edge and leaves the output handle
        untouched, while CommonResources destroys every handle that is not
        VK_NULL_HANDLE - sixteen refused samplers were destroyed as if real and the
        driver asserted. The array is cleared before it is filled.
  0018  the khr_display context reported quit from the frontend's signal-handler
        state, so the runloop ended on its first iteration and rarch_main returned 0
        with no frame drawn. A console title has no terminal and no SIGTERM sender.

The fourth is this port's own CRT: _start went from _init_env straight to the static
constructors and never cleared the BSS, whose tail is 0xc7040 bytes of a segment that
is 0x104b4 bytes in the file. tooling/native/ps5-pie.ld marks __bss_start/__bss_end
and _start clears that range; every run prints the check that says so. Whether the
loader also zeroed it was never measured - the invariant is what this asserts.

Two instruments, both because nothing else could be read:

  src/main.cpp sends stderr to /app0/trace.txt and makes it unbuffered. The driver's
  __assert prints the expression, file and line to stderr and then aborts, and the
  console's libc buffers that stream, so every assertion arrived as a bare `abort is
  called(system)`. The trace now carries the assert text, which is what identified the
  render-pass state as the current blocker.

  tools/apply-runtime-probes.py carries thirty-nine probes, and tests/test_frontend.py
  checks the set itself: an insert that ends with its own anchor duplicates the line it
  is inserted before, which broke the build three times in this round. Every probe must
  carry a marker in its own text, a note and a trailing newline.

Evidence: bash tools/run-title.sh with the probe set applied (captures under klog/,
probes reverted before this commit); the trace's own lines quoted above;
bash tools/verify.sh PASS with a probe-free image (`strings build/llvm-pie.elf |
grep -c 'probe PIPE2|probe VDRV|...' ` = 0 after deleting build/ra/obj, which is what
a revert needs); 20 unit tests including the probe-set checks.

Next: mark the span between the offscreen-passes call and the backbuffer pass - the
first-frame history/feedback clear and the menu texture upload - and fix whichever of
the two leaves a render pass open.
2026-09-19 01:03:05 -04:00
Mihawk 1327ad1da7 Remove the filter-chain stub, so the Vulkan driver has a shader path at all
With the driver linked and its five contract refusals fixed, vulkan_init still
returned NULL at the stock shader's pipeline and nothing said why. The reason was
in this repository: src/video_filters_stub.cpp, written when the port had video
filters disabled, defines the whole Vulkan filter chain as NULL-returning stubs.
src/ is linked before the archives, so the stubs won and the driver read "no
chain" - vulkan_filter_chain_create_default was never the real one, no pipeline
was ever built, and neither the log nor the trace could say so. Its own header
said this file is what has to go when the port grows shader support.

Removing it links glslang and SPIRV-Cross into the title, which are written
against FreeBSD's xlocale interface: the console SDK exports the unsuffixed
functions and none of the thirty-four `_l` ones the link then named.
src/locale_shims.c supplies them - each the C-locale answer its counterpart
gives, which is the only locale a title has - and implements the two the SDK has
no base function for (mbsnrtowcs, wcsnrtombs). nl_langinfo(RADIXCHAR) answers
".": SPIRV-Cross reads it to print shader constants.

src/main.cpp now points stderr at /app0/trace.txt. A title's stderr reaches
nothing on this console, which is why no library message - including an
assertion's - could be read; the marks and the library output are one record now.
It also installs a terminate handler naming an uncaught exception's type, which
is how an abort with no message was ruled not to be one.

What the console shows today, in order: video_vulkan selected, khr_display
resolved, device and swapchain created, four textures, a vertex buffer bound,
the stock SPIR-V reflected, both shader modules compiled, and then
vkCreateGraphicsPipelines returning VK_ERROR_UNKNOWN. Both stock shaders compile
through ../PS5_Vulkan's host compiler with the driver's own options, so the
refusal is in the console-only step after that - sceAgcCreateShader and
sceAgcLinkShaders inside ps5vk_graphics_pipeline_create, whose failure message
that project compiles out of its own build (#if !MESA_DEBUG in its vk_log.c).

Evidence: bash tools/run-title.sh with the probe set applied (captures under
klog/, twenty-nine probes, all reverted before this commit); python3
tools/symbolize-crash.py on each capture; the host compiler run on the extracted
stock SPIR-V (both stages, driver options); bash tools/verify.sh PASS with the
shipping image free of probes (`strings build/llvm-pie.elf | grep -c probe` = 0);
18 unit tests.

Next: that driver's sceAgcCreateShader/sceAgcLinkShaders result code, which only
its side can read.
2026-09-19 00:07:31 -04:00