Changes MapPixelFormatToGuestTextureFormat to default to format 56 (8-bit
RGBA) when the game uses a pixel format not yet in the known list, with a
stderr warning that reports the exact format value for project issue reports.
Previously, unknown formats returned 0, which caused RegisterKnownDisplayBuffer
to skip registration entirely. The GPU backend then couldn't find the buffer
during flip, producing vk.flip_capture_failed, and some games later hit a
Debug.Assert in ExecuteOrderedGuestFlipWait.
The fallback produces wrong colors for the affected games but lets them render
and display output, which is strictly better than a black screen or access
violation crash. The pixel format is printed to stderr so developers can
identify it and add proper support.
Co-authored-by: meowman <haadii2005@gamil.com>
* [SaveData] Implement save data memory2 exports
Astro Bot calls sceSaveDataSetupSaveDataMemory2 during boot and asserts
and null-writes when it fails, so the missing import surfaces as a
named crash. This implements setup plus the companion get, set, and
sync operations that make it useful. The store is one zero-filled file
per user and title at sce_sdmemory/memory.dat under the save root,
readiness is the backing file's existence, and get, set, and sync
return MEMORY_NOT_READY before setup. Struct offsets follow the
publicly documented homebrew savedata headers.
* [SaveData] Write setup result before mutating the memory backing file
Astro Bot asserts and null-writes when a subsystem init call fails, so
each missing import surfaces as a named crash. This stubs the blockers
observed during bring-up: content export init, eight font calls, and
pad tilt correction. sceFontGetHorizontalLayout writes the same
invented geometry as sceFontGetRenderCharGlyphMetrics and the rest
report success. Together with save data memory2 these take the title
to its splash image and font glyph rendering path.
* Implement DescribeAddressForDiagnostics method
Added a method to describe the state of a memory address for diagnostics.
* core: enrich allocation failure exception with host region diagnostic
* Latest commit info axamal structure
* Link latest commit to text
* Added localization for About>Last commit info
* Made the commit hash a button that redirects you to the commit in github
* Reorder about section
* Commit and update icon in about section to have consistency in section
Adds decode and SPIR-V translation for the missing MUBUF, MIMG and DS
atomic instructions in the Gen5 shader translator, generalizing the
existing BufferAtomicAdd path. Covers swap, cmpswap, add, sub,
smin/smax, umin/umax, and/or/xor, inc and dec, plus the DS RTN
variants. Image atomics go through OpImageTexelPointer on the storage
image binding.
Notable: DS_CMPST operand order (DATA0 = comparator, DATA1 = new
value) is reversed relative to buffer/image cmpswap, which a dedicated
test locks in. ATOMIC_INC/DEC are approximated with
OpAtomicIIncrement/IDecrement, exact for the common 0xFFFFFFFF clamp.
Verified with 9 new synthetic decoder and end-to-end SPIR-V tests
(part of the #36 test corpus effort); full suite passes 35/35.
Signed-off-by: missatjuhvdk1 <177474143+missatjuhvdk1@users.noreply.github.com>
Co-authored-by: missatjuhvdk1 <177474143+missatjuhvdk1@users.noreply.github.com>
## What
The native backend runs guest code directly on the host CPU. When the host doesn't
implement a BMI1/BMI2/ABM instruction that the PS5's Zen 2 cores do, it raises #UD
(STATUS_ILLEGAL_INSTRUCTION). Today the vectored handler just logs the faulting bytes
and gives up, so the title dies.
This adds a software fallback. On an illegal-instruction fault we decode the opcode
with Iced (the decoder already used elsewhere in the backend), evaluate it against the
trapped register/memory state, write the result and flags back into the CONTEXT record,
step RIP past the instruction, and resume.
Instructions covered (32- and 64-bit): ANDN, BLSI, BLSMSK, BLSR, BEXTR, BZHI, TZCNT,
LZCNT, RORX, SARX, SHLX, SHRX, PDEP, PEXT.
## Why
Users on CPUs without these extensions currently can't get past code that uses them.
This is a generic fix (no game-specific hacks) that improves compatibility on older
hosts. MULX is intentionally left out for now — its dest_hi/dest_lo operand ordering
is easy to get subtly wrong, so I'd rather add it separately with its own tests.
## How it's structured
- `BmiInstructionEmulator` holds the pure bit/flag semantics with no dependency on the
unsafe CONTEXT plumbing, so it can be unit-tested directly.
- `DirectExecutionBackend.IllegalInstruction.cs` is the thin unsafe adapter (decode →
read operands → emulate → write back → advance RIP). Anything it doesn't fully model
returns false and falls through to the existing diagnostics unchanged, so it can never
mis-handle an opcode it doesn't recognize.
- One hook in `DirectExecutionBackend.Exceptions.cs`, next to the other TryRecover* calls.
- Emits a single one-time "emulating in software" log line, not per-instruction spam.
## How I verified
- Added xUnit tests covering every instruction in both widths plus the CF/ZF/SF/OF
edge cases (src == 0, shift-count masking, index beyond operand width, etc.).
- Cross-checked all the expected values against an independent reference implementation
written from the Intel/AMD definitions; results match.
- `dotnet build` + `dotnet test` pass locally.
## Notes
New files follow .editorconfig (4-space, SPDX headers, REUSE-compliant).
* [Perf] Gate event-flag tracing so it allocates nothing when disabled
TraceEventFlag built its interpolated argument (and, on the wait path,
FormatFrameChain + a new StringBuilder(256) in FormatGuestWaitObject plus
~12 guest-memory reads) on every call, then checked the env var inside the
method — so every sceKernelSetEventFlag/Clear/Poll/Wait paid a string
allocation and an Environment.GetEnvironmentVariable P/Invoke even with
tracing off. Cache the flag once in a static readonly bool and gate every
call site, matching the semaphore/event-queue pattern. Behavior is
unchanged when SHARPEMU_LOG_EVENT_FLAG=1.
* [Perf] Hoist IsNoBlockLeaf classification to import-stub setup
The leaf-dispatch path called IsNoBlockLeafImport(nid) — a ~30-literal
string pattern match — on every leaf import. IsLeaf/NidHash were already
precomputed on ImportStubEntry at stub setup; add IsNoBlockLeaf alongside
them and read the field in the hot path. Behavior unchanged.
* [Perf] Cache trace env-var flags read on hot paths
Two SHARPEMU_LOG_* env vars were read via Environment.GetEnvironmentVariable
(a P/Invoke + transient string) on hot paths: SHARPEMU_LOG_FIBER on every
fiber context transfer, and SHARPEMU_LOG_DIRECT_MEMORY on every direct-memory
op (~8 sites). Cache both once — _logFiber alongside the other backend _log*
flags, and _traceDirectMemory behind the existing ShouldTraceDirectMemory
helper. Behavior unchanged.
* [Perf] Avoid per-iteration thread snapshot in the idle pump loop
PumpUntilGuestThreadsIdle allocated a full GuestThreadState[] snapshot
(via LINQ Values.ToArray()) on every spin just to tally three run-state
booleans. Tally them under the lock with an allocation-free helper, and
only materialize the snapshot inside the gated (default-off) diagnostic
dump. SnapshotGuestThreads now uses Values.CopyTo instead of LINQ.
Behavior unchanged.
* [Perf] De-LINQ GetPixelColorExportMask on the per-draw path
GetPixelColorExportMask ran a Select/OfType/Where/Aggregate chain over all
shader instructions, allocating iterators + closures, and is called per
render target (twice per draw via CreateRenderState and HasPixelColorExport).
Replace with a manual scan producing the identical mask — no allocation, and
it removes an authored-LINQ use the repo bans.
* [Perf] De-LINQ per-draw render-target selection in AgcExports
The bound-render-target selection used Where(...).OrderBy(...).ToArray()
(plus a second Where/ToArray fallback) on every translated draw, allocating
LINQ iterators + closures. Replace with an explicit filter into a pre-sized
list + List.Sort by slot; slots are distinct so this matches the stable
OrderBy. Same result, no per-draw LINQ allocations.
* [Perf] De-LINQ per-draw render-target validation in the Vulkan presenter
SubmitOffscreenTranslatedDraw validated its render targets with
targets.Any(...) twice plus targets.Select(a=>a.Address).Distinct().Count()
(a per-draw HashSet), and broadcast a single blend with
Enumerable.Repeat(...).ToArray(). Targets are <= 8, so replace with manual
scans (invalid-target check; combined dimension-mismatch + pairwise
aliasing check) and Array.Fill. Same results, no per-draw LINQ allocations.
* [Perf] Binary-search VirtualQuery region lookup (SortedList)
_mappedRegions was an unordered Dictionary, so TryFindVirtualQueryRegionLocked
scanned every region for containment/next — O(n) per sceKernelVirtualQuery and
O(n^2) when an allocator walks the address space with the findNext flag. Store
regions in a SortedList keyed by base address (every write already uses the
region's own address as the key) and find the containing/next region with a
binary search over the sorted keys. Also drops a now-redundant Values.OrderBy.
Non-overlapping regions assumed (mmap semantics), so only the floor region can
contain the query. Behavior-preserving; worth spot-checking VirtualQuery-heavy
titles.
* [Perf] Remove stray CLI packages.lock.json committed by mistake
git add -A in an earlier commit swept in a regenerated
src/SharpEmu.CLI/packages.lock.json. main tracks no lock files (central
package management, no RestorePackagesWithLockFile), and REUSE.toml no
longer covers packages.lock.json, so the committed file failed the REUSE
Compliance check. Remove it.
Each of the four byte-order helpers computed the swap into Rax and then
returned via ctx.SetReturn(0). SetReturn writes its argument into Rax, so it
immediately overwrote the converted value with 0 and the guest saw every
sceNetHtonl / sceNetHtons / sceNetNtohl / sceNetNtohs call return 0.
Leave the swapped value in Rax and return ORBIS_GEN2_OK as the dispatch status
instead, matching how the value-returning exports in this file (e.g.
sceNetPoolCreate) already work.
Add a NetExports test suite covering the swaps, the 16-bit width masking, an
htonl/ntohl round-trip, and a regression guard that a non-zero input never
converts to 0.
Quake (PPSA01880, Kex Engine) crashes at startup because
sceVideoOutIsOutputSupported (NID Nv8c-Kb+DUM) is unimplemented.
The game calls it to check video output capabilities before
initializing rendering.
Add HLE export stub: returns 1 (supported) for SceVideoOutBusTypeMain,
0 otherwise. The emulator renders via Vulkan and supports any pixel
format or aspect ratio on the main bus.
NID verified via Ps5Nid.Compute SHA1 algorithm.
Export name confirmed in scripts/ps5_names.txt.
* Boot compatibility fixes for UE titles, GUI toggles, and DeS render/boot work
Checkpoint of the Monster Truck Championship and Demon's Souls boot work.
Each piece is independently useful and verified against the titles.
- playgo: scePlayGoGetLocus now returns BAD_CHUNK_ID for chunk ids outside
the known set, matching real firmware. Titles enumerate chunk ids until
that error; answering OK for every id made the scan wrap the ushort range
and spin forever. Missing-sidecar and no-app0 fallbacks report a
fully-installed single chunk 0 so scePlayGoOpen keeps succeeding.
- kernel: restore the SHARPEMU_WRITABLE_APP0 opt-in. Unpackaged UE dumps
write their Saved tree under /app0 during PS5 component init and treat
the denial as a fatal boot error.
- pad: accept handle 0 as the primary pad across all pad calls. Real
firmware hands out small non-negative handles and some titles read state
with handle 0.
- bthid: env-gated experiment hooks for the Thrustmaster wheel middleware
investigation (fail-only-RegisterCallback modes and a synthetic
enumeration callback with a zeroed event struct). All default off.
- gui: add SHARPEMU_LOG_IO and SHARPEMU_WRITABLE_APP0 toggles to the
Environment tab.
- videoout: per-swapchain-image render-finished semaphores (the shared
semaphore raced the swapchain); whole-mip-chain layout init for offscreen
guest images (sampled binds read mips stuck in Undefined); GPU-resident
texture availability now canonicalizes through the texture format table
and accepts compatibility-class aliases, cutting per-frame CPU texture
re-reads (143 GB -> 55 GB per 300 s in Demon's Souls, 0.2 -> 0.5 fps).
- hle: add sceSystemServiceGetNoticeScreenSkipFlag,
sceSystemServiceGetMainAppTitleId (title id published from the runtime),
and sceNpWebApi2CreateUserContext (refuses so the online layer backs off).
- rtc: SHARPEMU_RTC_PROBE_RANGE diagnostic dumps the code around a busy-wait
caller of sceRtcGetCurrentTick once; costs nothing when unset.
* [ShaderCompiler] Fix VReadlaneB32 scalar destination field
The scalar destination lives in the low vdst byte (bits 0-7); it was read
from bits 8-14, the VOP3B carry-out field readlane does not have, sending
every readlane result to s0. Verified against raw gfx10 encodings and
LLVM's assembler tests (v_readlane_b32 s5, v1, s2 -> low byte 0x05).
* [VideoOut] Survive device loss and flip-order asserts without dying
Two ways a frame could take down the whole presenter:
- Device loss between any two Vulkan calls in a frame unwound the window
thread, and the Dispose-time fence check then threw again, masking the
original error. Catch the loss at the frame boundary, retire
presentations and guest submissions whose fences can never signal, and
keep the window loop pumping so the game (audio, logic) carries on.
- The ordered-flip capture invariant is violated ~100 times per run by
Demon's Souls (PPSA01342); on debug builds the Debug.Assert fail-fasts
the process with nothing in the log. Downgrade it to a once-per-version
warning until the capture/wait ordering is understood.
* Fix Dead Cells shader cache regression
---------
Co-authored-by: StealUrKill <35749471+StealUrKill@users.noreply.github.com>
* [Core] Add POSIX native execution and PS5 SELF support
Extend the native backend, guest TLS, fixed-address memory, and loader paths needed by PS5 titles on Windows, Linux, and macOS. Keep workstation GC so high-core-count hosts do not reserve over fixed guest image bases.
* [HLE] Expand PS5 service and media compatibility
Add the kernel, threading, save-data, networking, audio, video-codec, font, dialog, and service exports required by newer PS5 software. Preserve every SysAbi NID currently registered by main while adding the compatibility surface used by ASTRO BOT.
* [AGC/Vulkan] Extend Gen5 shader and presentation support
Expand PM4 handling, Gen5 shader translation, MRT and packed export support, guest image tracking, depth initialization, texture aliasing, and Vulkan presentation. Add the performance overlay and address-filtered diagnostics used to validate ASTRO BOT with original shaders.
* [Core] Align static TLS reservation across hosts
* [Pad] Align primary user ID with UserService
* [Gpu] Preserve runtime scalar buffers across renderer seam
* [AGC] Restore omitted command helper exports
* [Vulkan] Reuse primary views for promoted MRT targets
* [Vulkan] Preserve scratch storage bindings in compute dispatches
The PS5 image loader requires guest images to land at fixed virtual
addresses (e.g. the 32 GiB main image base). On macOS the exact-address
mmap path only ever passed that address as a hint, never MAP_FIXED, to
avoid clobbering untracked host mappings (dyld, JIT heap, Rosetta).
On Apple Silicon under Rosetta 2 the kernel does not reliably honor
that hint, so the allocation failed deterministically before a single
guest instruction ran (reported in #194). Retry with true MAP_FIXED
as a fallback only when the hint-only attempt doesn't land at the
requested address, so the safer hint path is still tried first.
VReadlaneB32 (VOP3 0x360) had two bugs:
1. Decode: VOP3 decode always set destinations = Vector(word & 0xFF).
For VReadlaneB32, bits 0-7 are unused — the scalar destination is
in bits 8-14. Now decodes as Scalar((word >> 8) & 0x7F).
2. Emission: VReadlaneB32 was in the VMovB32 fall-through group,
just returning GetRawSource(instruction, 0) — reading the current
lane's value. By ISA, sdst = vsrc0[lane(src1)], which requires
reading a different lane's value. Now uses SPIR-V
GroupNonUniformBroadcast(scope=Subgroup, value=src0, lane=src1)
when subgroup operations are available, with a fallback to the
current-lane simplification when not.
3. Routing: TryEmitVectorAlu called TryGetVectorDestination first,
which checks for VectorRegister kind. With the scalar destination
fix, VReadlaneB32 now routes to a new TryEmitReadlane handler
before the vector destination check.
4. Subgroup capability: UsesSubgroupShuffle now includes VReadlaneB32
so GroupNonUniform capability is enabled when needed.
Verified: dotnet build 0 errors/0 warnings, 26/26 tests pass,
ShaderDump all programs behaved as expected.