2026-11-12

RustPS5Emu v0.1.5-alpha

EmuCR: RustPS5EmuRustPS5Emu v0.1.5-alpha is released. RustPS5Emu is a compatibility layer for PS5 games, in the spirit of Wine: the game's x86-64 code runs natively on the host CPU; the system libraries (kernel, libc, graphics, audio, input, save data, networking, ...) are implemented in Rust (HLE); the GPU command stream is translated to Vulkan, and RDNA shaders are recompiled to SPIR-V.

RustPS5Emu Changelog:
Changed
The automatic choice of the recording thread (RPS5E_GPU_RECORD_THREAD=auto) no longer turns it off while the command interpreter also has to wait for room in its queue (RPS5E_POLICY_FULL). SILENT HILL: The Short Message's heavy room about 10 fps instead of 8; GTA V with RPS5E_BDA=1 47 fps instead of 42.
RPS5E_BDA=1 (experimental direct guest memory reads) no longer changes the default of RPS5E_LABELS_AT_EOP: with its old default (1) GTA V never left its start menu. GTA V's city in Performance mode with RPS5E_BDA=1: 47-48 fps against 37 without it; still off by default.
The emulator's own small writes into GPU-watched guest memory (memcpy/memset inside one page, packets of the command-buffer builders) mark the page written before the store instead of taking a page fault (RPS5E_PREMARK_SMALL). GTA V's city in Performance mode: write faults per frame ~1550 → ~320; over the same stretch of the scene the frame rate rises by about 2.5 % (36.6 → 37.4 fps).
Less overhead per draw in heavy scenes: the recording thread wakes the command interpreter once per half queue instead of once per command (RPS5E_QUEUE_WAKE_BATCH), and streams of page-sized buffer blocks share one buffer mirror instead of one per block (RPS5E_STREAM_ADJACENT). GTA V gains a few percent.
Shader programs are now decoded and planned on a worker thread as soon as the game creates the shader object (sceAgcCreateShader), not inside the first draw that uses them; the draw takes the finished program (RPS5E_CREATE_TIME_SHADERS=0 turns it off).
Fixed shader planning that could take seconds (or never finish) on programs whose buffer descriptors are computed through long chains of shared values.
Shader objects the game creates (sceAgcCreateShader) now move the prewarm work of their programs to the front of the shader prewarm list while it builds in the background, so those modules and pipelines are ready before the draws that use them (RPS5E_CREATE_TIME_SHADERS=0 turns it off). Modules are still made per draw permutation: what a module depends on (resources, render targets, vertex layout) is only known at the draw.
GRAND THEFT AUTO V's city: the GPU recording thread polls the GPU timeline briefly before blocking in the driver (RPS5E_GPU_WAIT_SPIN, in-run A/B +5.2 % flips), lookups of write-back spans skip long spans far from the range (RPS5E_THROUGH_LONG_BOUND, +3.5 % flips, recorder CPU per frame -5 %), and image eviction and repeated GPU-write records do less work. Frames of the captured city frames are byte-identical.
RPS5E_HW_RT=1 (off by default, experimental): hardware ray tracing for guest BVH traversals on devices with VK_KHR_ray_query. The host mirrors the BVHs the game's ray-tracing shaders traverse as Vulkan acceleration structures (triangles from the guest's triangle nodes, opacity and instance flags carried over), updated once per frame and refitting only the BLASes whose triangles changed (~1 ms of GPU a frame in GTA V's city, was ~4). The shader translator recognises the game's traversal loops (a node stack kept in VGPR lanes over image_bvh_intersect_ray queries) and gives them a copy whose nodes come from host ray queries: the RT cores find the candidates, the game's own instance, alpha-test and hit code runs on them unchanged, and instances the host has no mirror for are walked by the game's own loop. In GTA V's city the shadow traversal takes less GPU time in streets and alleys (~5 vs 7-10 ms a frame) but more in foliage-heavy views, so it stays off. The host queries cull the same triangle faces as the game's facing test (they culled the opposite ones, so non-opaque single-sided geometry such as Franklin cast no shadow with it). RPS5E_HW_RT_PRUNE=1 keeps the earlier box pruning for traversals without a copy; RPS5E_HW_RT=2 adds counters (diagnostics); RPS5E_HW_RT_DUMP= writes the guest BVHs it sees.
GRAND THEFT AUTO V's city runs about 35 % faster with all the changes below (user's city recording, frames after the 3rd Triangle, quiet machine: 0.1.4-alpha 8.0-8.3 fps → 11.0). Compute pipelines whose shader the GPU driver compiles with register spills are built again in the background from the same program translated with the emulated f32 denormal flush kept, and that build replaces the first one when it spills less (RPS5E_SPILL_VARIANTS, needs VK_KHR_pipeline_executable_properties). Both compute the same results; on an RTX 5090 GTA V's ray-tracing traversal no longer spills (168 → 223 registers, 160 bytes of spills → none) and takes 40-65 % less GPU time (city 37 → 20 ms per frame, open road 121 → 44 ms).
End-of-pipe labels now reach guest memory once the GPU has finished the work before them, as on the console, while the GPU command processor's own waits see them as soon as that work is recorded (the default; RPS5E_LABELS_AT_EOP=0 writes them as soon as the work is recorded, as before). A game thread that reads GPU results after such a label then finds them in memory instead of waiting for all queued GPU work while holding the GPU back-end (GTA V's main thread does that every frame: its city runs ~15 % faster, 10.7 → 12.6 fps in two alternating runs each). Marvel's Spider-Man 2 plays its intro videos ~25 % slower (~51 → ~38 fps): its command processor waits there for labels its own command buffers release, which now means waiting for the GPU, as on the console; its menus run as before. A GPU queue that waited for such a label before it landed makes its next memory write only once the label is in memory, as on the console (RPS5E_LATE_WRITE_ORDER): before, Demon's Souls and Minecraft, which keep labels inside their command buffers, could see the later write first, reuse the command buffer, and have the label land over their new commands (bad packet header 0x00000001, then a freeze).
GRAND THEFT AUTO V's city: another ~4-5 % (two in-run A/Bs: +5.5 % and +3.7 % flips, ahead in 10 of 14 10-second windows with 3 ties; the GPU's time per frame down ~5 %). In a run of back-to-back indirect dispatches with thread counts where every dispatch is followed by a barrier (GTA V's ray-tracing structure updates, ~300 a frame, each written back to guest memory), the thread-count kernels started a new launch batch at every other dispatch; each batch split the command buffer twice and added two full barriers. Such a run now records its kernels next to the dispatches once a batch held a single kernel (RPS5E_LAUNCH_BATCH_SINGLES, default on).
GRAND THEFT AUTO V's city: another ~10-20 % (three in-run A/Bs: +21 %, +23 % and +12 % flips, ahead in 21 of 24 10-second windows). The copies that bring compute results back to guest memory now follow the whole run of dispatches that wrote them, behind one barrier, instead of each dispatch (RPS5E_THROUGH_RUNS, default on); a copy needs the compute work before it finished, so a copy after every dispatch made the GPU finish each dispatch before the next could start. GTA V's ray-tracing structure updates (~2000 small dispatches a frame) were drained that way; the GPU now has ~95 % fewer such barriers and ~28 % fewer copies (a range an earlier copy of the same batch covered gets none: RPS5E_THROUGH_DEDUPE), its time per frame is ~10 % lower, and the GPU command recorder's waits for that work (~15 ms a frame) mostly went. Same pictures (capture replay frames byte-identical).
A new GPU buffer whose pages go into two device-address page tables gets one full barrier after both instead of one after each (RPS5E_TABLE_BARRIER_MERGE).
The GPU profile (RPS5E_GPU_PROFILE=1, used by input-test replays) costs the GPU command recorder about half as much: its spans are timed with the CPU's time stamp counter instead of the system clock (RPS5E_PROFILE_TSC), and the thread CPU time of draws (a system call) is read on one draw in eight (RPS5E_PROFILE_CPU_EVERY). GTA V's capture: recorder time with the profile 42 → 37 ms per frame (without it 34 → 33).
Shader LDS float minimum and maximum atomics (DS_MIN_F32 / DS_MAX_F32) are one integer atomic when the source is +0, an infinity or a normal number, instead of a compare-exchange loop (RPS5E_DS_INT_MIN_MAX, default on; the same words bit for bit). GTA V's per-object ray-tracing structure builds use them to merge child bounds: their GPU time drops ~14 % (capture replay, same frames). Games translate their shaders once more on the first start.
The GPU command recorder does less bookkeeping per draw and dispatch (GTA V's city: its CPU time per draw ~5 % lower in an in-run A/B, per item ~1-3 % overall; the frame rate moved by less than the run-to-run spread, ~12.4 → ~12.6 fps): before work that reads memory through unbounded device addresses only the buffers the CPU wrote since the previous time are looked at, from the tracker's log of CPU writes, instead of every buffer (RPS5E_UNRANGED_LOG); a range is checked for watchability against the page registry before the memory-layout memo (RPS5E_REGISTERED_FIRST); the buffer holding a range is found from the per-page index alone (RPS5E_INDEX_EXTENTS); long write-back spans no longer widen every span lookup (RPS5E_THROUGH_LONG); the recorder's own timing reads the time stamp counter instead of the system clock. All on by default; the same pictures (capture replay frames byte-identical).
With RPS5E_AB_PERIOD, the [gpu] line also counts dispatches and their recording CPU time per A/B mode (ab_dispatches, ab_dispatch_cpu_ms).
Diagnostics for the GPU command recorder's waits: RPS5E_WORD_SPECULATION=check compares every GPU-written word a shader's preparation waits for with the value guest memory held before, times the wait by whether all GPU work writing the word had already finished, and names the draw or dispatch that wrote it; RPS5E_PM4_BLOCKED_WHY=1 sums the time all GPU command queues were blocked by what each queue waited for; RPS5E_WRITE_RANGE_CHECKS=1 makes device-address stores count the ones outside the range the host planned for them. All off. Games translate their shaders once more on the first start.
RPS5E_WAIT_TRACE_TICKS=1 (with RPS5E_WAIT_TRACE and the GPU profile) logs every command buffer's GPU time and the GPU's idle time before it; frame-trace lines (RPS5E_FRAME_TRACE) show the guest queue of every draw and dispatch.
RPS5E_ITEM_CPU=1 also lists, per program, the barriers, submits and write-through copies each draw or dispatch recorded; RPS5E_BARRIER_SITES=1 counts full barriers per call site and program; the [gpu] line counts compute and transfer-read barriers and write-through copies.
RPS5E_PIPELINE_STATS=1 logs the guest program address of each compute pipeline.
RPS5E_WAIT_TRACE= (diagnostics) logs the GPU command recorder's long waits for the GPU with the submissions they waited for and, with the GPU profile, the GPU time and idle time of each.
Fixed
Ray-tracing shaders now intersect BVH triangle nodes of types 2 and 3 (the node's triangles v2 v3 v4 and v2 v4 v0, as the guest's BVH builders lay them out); only types 0 and 1 were tested before, so ~9 % of GTA V's shadow-casting triangles never cast a shadow.
The GPU profile (RPS5E_GPU_PROFILE=1) lost the GPU time of a submission's earlier command buffers and of its launch batches whenever a launch batch split the submission: the time is now counted, and the batches show as chained. GTA V's city was under-reported by ~25-30 ms per frame (real GPU time ~80-85 ms per frame, not ~51).
RPS5E_FRAME_TIMES files are appended every second instead of being written at shutdown (and every 1024 frames): a run stopped by a timeout no longer leaves a file cut at 2048 frames.
sceKernelMprotect / mprotect over a range that starts in unmapped memory, or that has nothing mapped at all, now changes the mapped pages and returns 0 as the console does (was EINVAL). sceKernelMtypeprotect over a range holding flexible memory returns EOPNOTSUPP (0x8002002D) and changes nothing, as on the console.
sceKernelSignalSema with a count of 0 returns EINVAL as on the console (was 0).
sceKernelWaitEqueue checks the event count before the queue and stores 0 events on every failure.
sceVideoOutRegisterBuffers / sceVideoOutRegisterBuffers2 over buffer slots that are still registered return SLOT_OCCUPIED (0x80290010) instead of RESOURCE_BUSY.
sceNetResolverStartNtoa: a timeout of 0 stands for one second and a timeout under one second is EINVAL; an unknown resolver id is reported before a missing host name or address, as the system library does.
Shaders: v_mad_u32_u16 / v_mad_i32_i16 honour op_sel bits 2 and 3 (high half of the 32-bit addend; result into the high half), checked against RDNA2 hardware results; an f64 result clamp keeps a NaN when DX10_CLAMP is off, like f32 and f16; v_div_fmas_f32 flushes a denormal result in the f32 modes that flush results (its inputs stay unflushed). Games translate their shaders once more on the first start.
After a context clear the four clip rectangles are (0, 0)-(8192, 8192), as in the system's register defaults, instead of empty: a clip-rectangle rule set without writing the rectangles no longer hides every draw.
Windows: guest threads start with the console's x87 control word (64-bit precision) instead of Windows' 53-bit one, so the games' long double arithmetic is no longer rounded short.

Download: RustPS5Emu v0.1.5-alpha
Source:Here

0 Comments

Post a Comment