14 of the 15 upstream commits since bab81aa23. The fifteenth, 3aea3b15d 'Fix
ISO timestamps', is deliberately left out: it touches rpcs3/Loader/ISO.cpp,
and the Aug-2026 upstream ISO refactor is already reverted here because it
breaks some images (region_count reads 0 and the disc will not mount). It is
the tip commit, so merging its parent excluded it exactly, with no surgery.
Four conflicts, all of them ours-and-theirs rather than either-or:
nv4097.cpp conflicted whole-file. Took ours and applied upstream 071c9f10f's
set_shading_mode by hand -- an earlier merge of this same file lost two hunks
by resolving it wholesale, and that is recorded in c6a0878a9.
VKPipelineCompiler.cpp: ours has the mobile dynamic-state work (topology-class
collapsing, normalize_dynamic_pipeline_state, compiler thread affinity),
upstream adds a provoking-vertex chain for flat shading. They are independent,
so both are in, with the rasterization state rebased as upstream needs.
device.cpp: three hunks, all parallel feature queries -- extended dynamic
state and the Android LSFG feature bits on our side, provoking vertex on
theirs. All kept; ours' extension push needed its own closing brace.
BUILDING.md stays deleted: 30fc4e566 folded it into the README, and upstream
merely edited it.
Core builds and links.
load_iso() cannot report failure: it mounts the virtual device whether or
not the archive actually opened. An image that is unreadable, truncated,
or encrypted without a usable disc key therefore sailed past the mount and
died much further down as a generic 'invalid file or folder', with nothing
in the log distinguishing it from a dozen other causes. A bug report of
that failure carries no information at all.
Check the mount where the reason is still knowable. An image whose
filesystem did not parse now reports whether a disc key was missing or
rejected -- returning decryption_error, and naming both the key locations
searched -- or, failing that, says the image looks truncated. When the
archive is readable but has no EBOOT.BIN at the expected path, log what the
disc root did contain; install discs legitimately lack one, so that stays a
warning rather than a failure.
Also realign BootResult with game_boot_result. It was missing
firmware_version and database_config_missing, so every code from ordinal 10
down was reported as its neighbour -- still_running surfaced as
'AlreadyAdded' -- and the last two had no entry at all, making fromInt
throw rather than return. fromInt is now total.
Refs #88
Reverts upstream 8a6c96745, taken in the ROP remap merge, back to the 0.8
behaviour. The check is sound on a desktop filesystem, but on Android the disc is
read through SAF/content URIs and this predicate decides how a title gets
mounted: System.cpp:1572, 1589, 1764 and 1878 all branch on it, as does
rpcsx-android.cpp:3935. A short read there does not fail the boot outright, it
silently routes the title down a different mount path -- which is what a game
that reaches its first loading screen and never leaves it looks like.
Not identical to 0.8: magic[] is zero-initialised. The original compared it
without checking the read at all, so a failed read compared uninitialised stack.
Zeroing restores "do not reject on a short read" without the undefined behaviour,
and a genuinely non-ISO file still fails the CD001 test.
iso_archive::is_valid() stays. It comes from a different upstream commit
(d6d5c6082), System.cpp calls it, and it is not part of this predicate.
Reported against NASCAR 2011, which reached the menus before the merge and now
sticks on the first loading screen. NOT confirmed as the cause -- the reporter's
build predates the local commits, and the other public candidates in that window
are the Adreno compute group size and the driver pipeline cache work.
Seventeen commits. The substantial one is kd-11's ROP_OUTPUT_REMAP series
across rsx/fp, glsl and both backends, which ARMSX3 did not have at all.
Two conflicts.
nv4097.cpp: upstream added the ROP remap plumbing to the format-change checks,
we have profiler instrumentation and an ARM64 observe() on the two hot FIFO
reads. Different parts of the same file, so upstream's version is the base and
ours is re-applied on top. The g_xform_const_words increment is included
deliberately: the profiler reports average batch size as words/calls, so
dropping it would have printed 0 rather than nothing, which is worse than an
absent stat.
ISO.cpp: took upstream's magic-read check. It is a real fix --
`!file.read_at(...) == 5` parses as `(!x) == 5`, which is false for every x, so
the guard never fired and a short read left `magic` uninitialised. Our reverted
reader has no check there at all, and read_at returns a byte count in this
version too, so the corrected form applies cleanly.
This does NOT undo the ISO reader revert. The refactor that broke reading for
some users is still reverted; only the one-line magic check comes across.
The upstream merge brought a six-commit ISO series that regressed reading on
some images. A tester's ISOs that loaded on 0.9.2 now fail at the very first
header read:
ISO: init: Failed to read region information (region_count=0)
ISO: iso_archive: Corrupt ISO file: Decryption failed
Both of his games fail identically, so it is not one bad dump, and other
people's ISOs still load, so it depends on the image format -- most likely the
3k3y path, which has its own watermark detection and key extraction at 0xF70
and 0xF80, separate from the plain one.
The reader is reverted to its 0.9.2 state. The change implicated is the region
count read moving from char_arr_BE_to_uint(sec0_sec1.data()) to
read_from_ptr<be_t<u32>>(sec0_sec1), alongside decrypt_data moving from raw
pointers to std::span, but this is not a targeted fix: it restores code that
demonstrably worked rather than guessing which line of the refactor is wrong.
is_valid() is kept, because System.cpp calls it and it is one line that has
nothing to do with the failure.
What this gives up is real: the series contained out-of-bounds write and
overflow hardening for ISO parsing. A reader that cannot open a user's games
is the worse of the two, and the hardening should come back with a version of
the refactor that works. The path validation from the same series that lives
outside these two files is untouched.
Unverified against the actual failure -- the ISOs here all load either way, so
this could not be reproduced locally. It is verified not to break what already
worked.
Catches up 98 commits from RPCS3/rpcs3. Seven files conflicted:
PPUTranslator.cpp -- upstream fixed the ARM64 float-to-int saturation
inversion independently, and the two fixes are the same fix. Took upstream's
ordering so it stops re-conflicting, kept one line of the reasoning.
rpcn_types.h, rpcn_client.cpp -- our hand-rolled protocol 31 bump was a
stopgap to stop the server refusing us. Upstream's trophy sync (cb175278b) is
the real implementation, so it replaces ours outright.
nv0039.cpp -- upstream refactored the strided copy and extracted
validate_buffer_notify; ours was the older code plus a profiler include. Took
upstream's, re-added the include.
VKQueryPool.cpp -- both sides had real changes. Upstream added a lock around
the pool cache; ours has the bounded occlusion-query wait and the render-pass
fix for the Adreno device loss. Kept ours, re-applied their lock.
VKResourceManager.cpp -- upstream moved GC completion onto a
driver_manager_thread, which supersedes our flush parameter and offloader
dispatch entirely. Took theirs; no callers passed the second argument.
VKGSRender.cpp -- our flush-site counter and their driver-manager drain are
independent. Both kept.
Upstream also began attaching 3D and array levels through DSA, which
EXT_direct_state_access has no NamedFramebufferTextureLayer for, so the GLES
shim gains one that binds and uses the non-DSA entry point.
Reverted in the same commit, because they are what is on the tester's device
and it is broken: the sync-fd handoff, the SUBOPTIMAL acquire fix, the
cross-device ownership barrier, the generated-frame acquire semaphore, and the
deferred-present guard in frame_context_cleanup. Each was defensible on its
own reading of the code and the result was worse every time -- slower, judder
described as nauseating, and rendering faults that outlast switching frame
generation off. Five attempts is enough to stop treating the next theory as
better than the last.
What stays fixed is everything outside the present path. What goes back is the
state before tonight: frame generation is slow and does not release its memory
when switched off.
Adds an Android build of the RPCS3 core plus a Compose UI, and fixes several
things that stopped it working on ARM64.
Renderer:
- Emit concrete bounds for runtime sized arrays in uniform blocks when
VK_EXT_shader_uniform_buffer_unsized_array is missing. Adreno does not have
the extension, so every game pipeline failed with VK_ERROR_UNKNOWN and only
overlays drew.
- Probe and request that extension properly instead of chaining its feature
struct unconditionally.
- Hand VMA the Vulkan function pointers it needs under VK_NO_PROTOTYPES.
- Rebuild the surface and swapchain when the window is lost instead of killing
the RSX thread.
- Only create a GLES context when the GL renderer is actually selected.
SPU:
- Sum instead of taking an absolute difference in the ARM64 block verification
checksum. The difference collides on the near identical job binaries an SPU
job manager streams through one local store address, so a cached block could
run against another job's code.
Threading:
- Implement thread affinity on Android using sched_setaffinity.
- Add an ARM big.LITTLE core arrangement so SPU and RSX threads land on the
fast cores.
Misc:
- Detect the host CPU for the LLVM JIT instead of pinning cortex-a34.
- Fall back to the default audio device when cubeb cannot enumerate.