Commit Graph

628 Commits

Author SHA1 Message Date
ParantezTech fb5b9c014e [SpirvTranslator] Read buffer stride and descriptor word 3 from portable buffer words 2026-10-09 17:59:18 +03:00
ParantezTech add35a79e6 [ShaderCompiler] Predict written formatted buffers for static specializations 2026-10-09 17:59:18 +03:00
ParantezTech 57846deed5 [ShaderCompiler] Canonicalize buffer specializations for portable descriptors 2026-10-09 17:59:18 +03:00
ParantezTech b8d86c27bf [ShaderCompiler] Reserve portable buffer descriptor words in the binding layout 2026-10-09 17:59:18 +03:00
ParantezTech 2e507d4e08 [ShaderCompiler] Track runtime reads with one visited set across branches 2026-10-09 17:59:17 +03:00
Berk f32266834c
[SharpEmu] Add bundled demo game (#1072) 2026-10-09 17:41:17 +03:00
ParantezTech 0af8dce081 [GUI] improve library tile collection and acceleration fixes 2026-10-09 14:55:12 +03:00
qwe1qwe 289f090b50
[GPU] Align linear color target pitch like linear textures (#1063) 2026-10-09 14:07:12 +03:00
Berk 47d4c07a8d
chore: bump version to 0.0.5-nexus-release.2 (#1070) 2026-10-09 01:53:47 +03:00
Berk 1811cef944
Ports another set of compatibility and GPU fixes from PR #1016 (#1069)
* [Cpu] Prefer LLE for libc FILE-object exports

* [Libc] Add file-lock compatibility exports

* [Kernel] Expose the process argument count and vector

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [AppContent] Report missing add-on content entitlements

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Videodec2] Decode guest access units into pitched NV12 frames

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Network] Add the RUDP context lifecycle

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [SharePlay] Report inactive share-play state

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Np] Complete offline authentication requests as signed out

* [Kernel] Warn when APR cannot resolve a resource path

* [GPU] Skip piece hashing for stencil association proxies

* [VideoOut] Add deduplicated volume texture binding traces

* [SpirvTranslator] Match guest F32 denormal and trigonometric semantics

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Network] Add socket epoll registration and readiness waits

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Network] Close POSIX socket descriptors through sceNetSocketClose

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Network] Add Ethernet address string conversion

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Json] Track the global special-float handler

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Json] Add the special-float format setter

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Pad] Add the n3kSX62fgNo compatibility export

* [Pad] Trace input state changes when requested

* [PlayGo] Keep unknown chunk lists empty

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [PlayGo] Keep chunk metadata parsing in the metadata loader

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [PlayGo] Expose runtime state reset

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [PlayGo] Add install and optional chunk queries

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Loader] Preserve switch targets while patching guest red-zone accesses

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Loader] Report patching progress for large executables

* [SpirvTranslator] Preserve F32 signed zero, infinity and NaN when supported

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [GPU] Use Gen5 render-target tile equations on the CPU and GPU

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [GPU] Decode DCC fixed and register clear values

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [GPU] Track DCC metadata coverage for color targets and volume textures

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [GPU] Materialize DCC slice clears from guest metadata

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Tests] Cover Gen5 tiling, DCC clears and offline authentication

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Tests] Match red-zone coverage to forward-only patching

* [Pad] Track independent standard, special and remote port handles

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [UserService] Add user number and termination exports

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [NP] Expose the game trials flag

* [Kernel] Allow renaming and unlinking open guest files

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Tests] Cover controller ports, user exports, trials and open-file renames

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Clear the outputs and report no space when no direct memory span is free

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Return POSIX results from _open and keep sceKernelOpen raw

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Open /dev/random and /dev/urandom as host RNG descriptors

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Read random device descriptors from the host RNG

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Close random device descriptors

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Report random device descriptors in fstat

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Cpu] Place the guest exception mcontext at the start of the context

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Cpu] Report the flags and Sony stack alias in guest exception contexts

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Cpu] Expose the guest exception context writer to tests

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [NP] Keep Universal Data System handles across repeated initialization

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [NP] Create Universal Data System contexts before explicit initialization

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [NP] Reset Universal Data System state with the runtime

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Pad] Write the device class extended information at its guest size

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Pad] Add scePadDeviceClassParseData

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Tests] Cover random devices, POSIX open, UDS initialization, pad class data and exception contexts

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [SaveData] Write the mount info structure at its 48-byte guest size

* [Stubs] Add sceTextToSpeech2Cancel and sceTextToSpeech2GetSpeechStatus

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Kernel] Add sceKernelSync

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>

* [Loader] Patch red-zone sites from the previous instruction when every indirect branch is resolved

* [Tests] Cover backward red-zone spans, direct memory no-space results and the mount info size

---------

Co-authored-by: Sekai <140012992+SekaixX@users.noreply.github.com>
2026-10-09 01:44:45 +03:00
Berk b02c06181a
Unity fixes 1016p2 (#1062)
* [Audio] Snapshot AudioOut2 PCM when the guest submits it

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Drop the ports of a destroyed AudioOut2 context

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Accept sceAudioOut2MasteringSetParam

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Resolve AudioOut2 out-buffers from either ABI slot

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Report the AudioOut2 context memory size through its out pointer

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Keep the AudioOut2 queue level and availability pointers apart

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Report full volume in the AudioOut2 port state

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Trace AudioOut2 port, attribute and bed calls

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Let tests replace the AudioOut2 host streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Audio] Add the AudioOut2 vibration port type

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [SaveData] Lay out save data events with their title ID

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [SaveData] Add sceSaveDataBackup

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [SaveData] Add sceSaveDataDirNameSearch2

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Network] Track Http2 template and request options

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Network] Add Http2 option, cookie and request exports

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [CommonDialog] Add the web browser dialog lifecycle

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Json] Add the InitParameter2 base constructor

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Json] Add InitParameterRtti2::setAllocatorRtti

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [AvPlayer] Accept available bandwidth hints

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Tests] Cover the AudioOut2, save data, Http2 and dialog exports

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

---------

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>
2026-10-07 18:47:42 +03:00
kuba e1edda7772
Revert the 18 Silent Hill rendering and performance merges (#1065)
Restore review-only delivery at the user request. Reverts #1024, #1025, #1031, #1032, #1033, #1034, #1035, #1036, #1037, #1038, #1039, #1040, #1041, #1051, #1054, #1055, #1058, and #1059. The resulting tree matches 3e2ad633 exactly.
2026-10-07 12:15:45 +02:00
kuba 775141d58c
[GPU] Sweep CPU writes at memory visibility points instead of before every device-address program (#1033)
* [GPU] Sweep CPU writes for device-address programs at memory visibility points

A device-address program may read any mapped page, so before each such
draw or dispatch the buffer cache uploaded every CPU-dirty page whenever
the global CPU-dirty epoch had moved. A guest that streams its per-draw
ring while the command stream is being translated moves the epoch between
almost every pair of draws, and each upload ended the rendering scope and
drained the GPU with an ALL_COMMANDS barrier pair - about 670 times per
frame in Silent Hill: The Short Message's menu.

CPU writes only need to be visible at memory visibility points: when a
submission slice starts, when a wait packet is satisfied, and after a
command-processor memory write (later commands may read those bytes through
device addresses). The sweep now runs at the first device-address program
after such a point, and its uploads share one barrier pair instead of one
per buffer. SHARPEMU_BDA_SWEEP_EVERY_DRAW=1 restores the per-draw sweep.
Menu GPU time drops from about 435 to 290 ms per frame.

(cherry picked from commit fafe92b71271cf750dd89251891bac20fb87f1ff)

* [GPU] Let command-processor DMA writes turn pages CPU-dirty instead of copying

A DMA fill or copy into memory without GPU-written bytes is executed on
the CPU, and the bytes were then pushed into every overlapping cache
buffer through a staging copy and a barrier pair, which ends the
rendering scope (~60 per frame in Silent Hill: The Short Message's menu).

When no GPU-written byte shares the written pages, the pages now simply
turn CPU-dirty: every later GPU reader synchronizes CPU-dirty pages before
reading (bound buffers on obtain, device-address programs at the next
memory visibility point, which the write now raises), so the bytes still
arrive in command order. Pages that hold GPU-written bytes keep the
staging copy. SHARPEMU_DEFER_HOST_WRITES=0 restores the copy.

(cherry picked from commit 3fe21faa3821551fa99b9398064f0652e45d2e84)

* [GPU] Keep hot CPU-written pages writable across device-address sweeps

A page the guest rewrites every frame turns hot after two upload/write
cycles, and the bound-buffer path then serves it from the stream ring so
the page stays writable. The device-address sweep and the range
synchronization still re-protected hot pages after every upload, so the
guest's next write to each ring page took a protection fault - about
5,000 faults per second on Silent Hill: The Short Message's render
thread, each a signal round trip under Rosetta plus page-guard lock
traffic shared with the command worker.

Both sweeps now preserve hot pages: they stay dirty and writable and are
copied again on the next sweep, a few hundred KiB of ring memory per
sweep. Faults drop to a third and the menu goes from 3.8 to 4.2 FPS.
SHARPEMU_BDA_SWEEP_REPROTECT_HOT=1 restores the re-protection.

(cherry picked from commit 65d2b55ddc07644d52e5ad3112cbe323a2421abd)

* [GPU] Refresh writable hot pages at every BDA visibility point
2026-10-07 11:52:12 +02:00
kuba 38f7196470
[GPU] Add internal render resolution scaling (#1038)
* [VideoOut] Add an internal render resolution scale option

Adds the host-side setting an internal-resolution implementation needs:
--render-scale on the command line, SHARPEMU_RENDER_SCALE for scripted
runs, and a global and per-game choice in the GUI. The value is a host
resolution multiplier of the guest render targets, normalized to a
hundredth in [0.25, 2] so the command line, the GUI and the environment
agree bit for bit; the renderer compares scales when it decides whether
two views of the same guest memory match.

RenderScalePolicy holds the decision rule. It is a pure function of the
guest image description, so every view, alias, copy and descriptor of
one guest range reaches the same answer without consulting the cache.
Only screen-class, single-level, single-sample, uncompressed 2D render
and depth targets scale; block grids, multisample footprints, HTile and
DCC coverage, mip chains, cube and array faces, asset tilings and small
surfaces (shadow maps, lookup tables, eye-adaptation readbacks) keep
their guest resolution. The environment variable wins over the stored
setting so test runs do not depend on the user's configuration.

No renderer consumes the scale yet; a scale of one is the current
behaviour everywhere.

* [GPU] Hold scalable guest images at a host render resolution

The backing of an image the scaling rules accept is created at
ceil(guest * scale) while its ImageDescription keeps the guest geometry,
so the cache, the overlap rules and the page tracker go on reasoning in
guest bytes.

Everything that moves guest bytes now goes through a guest-resolution
twin of the scaled image: an upload fills the twin from the copy regions
the tiler built and blits into the backing, a download blits the backing
into the twin and copies out of it. A copy whose two images disagree on
host resolution runs at guest resolution the same way, so callers keep
describing rectangles in guest pixels; the destination seeds its twin
first because a partial copy is blitted back whole. The multisample
depth conversion takes a guest-sized source for the same reason, and the
resolve region crosses into the destination's resolution instead of
silently resolving the top-left corner.

Two fallbacks keep correctness ahead of the saving. A format that cannot
blit keeps its guest resolution, since the twin could never reach it.
A storage image drops back to guest resolution the first time a compute
shader binds it: the dispatch grid does not shrink with the host image,
so the shader would write it with holes above 1.0 and redundantly below.
The guest range is remembered, so every later image over that memory is
created unscaled too.

* [GPU] Scale the render area, viewport and scissor with the attachments

A resolved target now reports the host extent of its attachment beside
the guest one, and the three places that size rasterization follow it:
the dynamic rendering area, which also bounds every load-op clear; the
guest viewport transform; and the guest scissor, whose edges round
outward so no guest pixel the game asked for loses host coverage.

All attachments of a pass share one rule, so the first bound target
decides the factor.

The clip-disable path needs care because the vertex program bakes the
viewport transform against a reference extent. Dividing that reference
by an upscale keeps the host viewport (reference x scale) inside the
device limit while the baked transform stays scale independent, so the
same program maps guest pixels onto host positions at either resolution.
At a scale of one the reference is the device limit, exactly as before.

* [SpirvTranslator] Translate pixel positions and image coordinates across the render scale

A program expresses its pixel position, its integer image coordinates
and the sizes it queries in guest pixels, but the host may hold the
image behind any of them at another size. Which images are scaled is a
per-draw fact, so the factors travel in shader data rather than in a
permutation: the coordinate factor, its reciprocal, a 64-bit mask of
scaled image resources and the factor the pixel position is divided by.

With that:

- gl_FragCoord is divided by the attachments' factor as it is loaded, so
  POS_X/POS_Y, POS_FIXED_PT and everything derived from them - screen
  UVs above all - stay in guest pixels.
- An integer image coordinate is mapped onto host texels through the
  bound image's factor. Only the two scaled axes move; an array layer or
  a volume slice is not a pixel.
- A resource-info query reports the guest size, because the program
  derives coordinates and loop bounds from it.

A select against the mask makes an unscaled binding cost one
instruction, and the layout only carries the dwords when the scale is
not one, so nothing changes at native resolution.

* [GPU] Keep one host resolution across the attachments of a pass

A rendering scope has one render area, one viewport and one scissor, so
its attachments have to agree on a host resolution. They disagree when
one of them cannot be scaled at all - a depth target with a stencil
plane next to a scalable colour target, say - and the pass then renders
a fraction of its area. The draw now drops every scaled attachment back
to guest resolution and resolves its targets again; the guest ranges are
remembered, so the decision converges after one draw and cannot
oscillate.

That fallback only works if the executor knows what the cache actually
gave it, which is not what the scaling rules would answer: a demoted
range still looks scalable to them. The resolved targets therefore carry
the image's own factor, and the render area, viewport, scissor and the
depth/stencil copy extent read it from there.

Two rules change with it. DCC only describes guest bytes the host never
stores, so a colour target that carries it can still be scaled; HTile
encodes guest depth blocks the renderer reads back as clear state and
stays native. And a storage image only drops back when the program
actually writes it, since a read-only load is mapped correctly.

Scaling now also requires a backend that installed the format
predicate - the Vulkan device - so the Metal host is unaffected.

* [Docs] Describe internal resolution scaling and its limits

Replaces the note saying arbitrary internal resolution scaling is not
implemented: it is, for screen-class render and depth targets. Records
what the renderer translates (rasterization, shader coordinates, guest
transfers, presentation), the exact rule for what scales, every case
that falls back to guest resolution, the artefacts measured on Silent
Hill, and the per-scope GPU times at 50, 100 and 200 percent.

* [SpirvTranslator] Preserve guest texel offsets at scaled resolutions
2026-10-07 11:47:58 +02:00
kuba 8acc081205
[GPU/HLE] Cut per-draw and per-call managed allocations on hot paths (#1054)
* [GPU/HLE] Cut per-draw and per-call allocations on hot paths

* [HLE] Keep nested tracker uploads from sharing rollback scratch
2026-10-07 11:36:27 +02:00
kuba 98f223ce69
[GPU] Restore scene visibility and half-wave shuffles (#1025)
* [Agc] Emit addressed draw events for occlusion query counters

* [Gpu] Keep fallback occlusion results coherent and conservatively visible

* [Gpu] Honor disabled color buffers during depth-only draws

* [Gpu] Upload complete unchecked constant vertex attributes

* [Agc] Emit direct draws for every draw modifier

sceAgcDcbDrawIndex and sceAgcDcbDrawIndexAuto returned without writing a
packet unless the modifier was exactly 0x40000000. The modifier names the
shader stage and user registers of the bound pipeline, so any other
pipeline lost its draws without a trace. Unreal bakes its color-grading
LUT through a geometry-stage pipeline, which left the LUT unwritten and
tinted every 3D frame of Poppy Playtime blue.

Both draws now emit their packets for any modifier. Modifiers other than
the vertex-stage default are logged once each.

(cherry picked from commit 8d46a6068b7d1a999662eeac1ee17f9e6d87c2eb)

* [VideoOut] Separate guest display mode from presentation buffer dimensions

* [GPU] Map half-wave shuffle lanes into the host subgroup

* [Docs] Explain display modes and internal resolution limitations

* [GUI] Translate guest display mode settings in all supported languages
2026-10-07 11:21:15 +02:00
kuba 8b631d3b03
[GPU] Avoid command-worker readbacks for clean bytes on GPU-dirty pages (#1059)
* [GPU] Read clean command bytes without faulting on neighbouring GPU data

* [Tests] Enable portable Vulkan devices and release fixture slabs
2026-10-07 11:21:09 +02:00
kuba a9356eb8d2
[GPU] Read guest buffers back from unified memory without a copy (#1058)
A CPU read of GPU-written guest memory recorded a copy at the tail of
the current command buffer and waited for it, so it also waited for
every draw recorded after the writer. In Silent Hill's title menu most
of those reads targeted buffers whose writer had retired long before,
and UE's render thread spent a third of its time in them.

On a device with device-local, host-visible, coherent memory (Apple
GPUs), guest buffers are now allocated there. A readback whose writers
retired copies straight out of the buffer's mapping; one whose writer
is submitted but still running waits for that submission alone and then
copies; the command worker submits a writer that is still recording
and reads after it. A guest-thread wait also marks its window hot, so
the next GPU write there is submitted right after its command.
SHARPEMU_UNIFIED_BUFFERS=0 keeps device-local buffers.
2026-10-07 11:02:22 +02:00
kuba a73e424a27
[macOS] Fix the Rosetta GC wedge, a CPU-flip buffer-wait deadlock and frozen host movies (#1051)
* [CLI] Restart under Rosetta with a 64 MiB gen0 GC budget

Every collection suspends the runtime through FlushProcessWriteBuffers,
which Rosetta 2 services by parking each thread in its runtime
(notify_thread_waiters). A signal that reaches a parked thread trips
Rosetta's "expected saved LR to be in translated code" assertion and
wedges the process; Demon's Souls hit it in about half of its 3-5 minute
runs while collecting almost twice a second. The gen0 budget is only read
from the environment, so the process re-executes itself once with
DOTNET_GCgen0size set (same pid). With 64 MiB, Demon's Souls collects
about once every 6 seconds, gen0 and gen1 only, 0.26 s of pauses in
110 s. A 512 MiB budget made every collection a blocking gen1/gen2 pass
of about a second. SHARPEMU_ROSETTA_GC_BUDGET=0 opts out.

* [VideoOut] Let a buffer wait ignore CPU flips the graphics queue has not reached

sceVideoOutSubmitFlip reserves its flip request, may sleep for pacing,
and only then queues the flip preparation on the graphics queue. A
command buffer submitted before it that starts with
sceAgcDcbWaitUntilSafeForRendering on the same display buffer saw the
reserved request as pending and waited for a preparation queued behind
itself: the graphics queue never advanced and every compute queue waiting
on its labels stalled with it. Demon's Souls hung this way on the boot
splash in about one run in three.

A CPU flip now counts for the wait only once the graphics queue runs its
preparation; GPU flips are ordered from their packet.

(cherry picked from commit 8915df35abad5fe8b15cc6418f1e563785d6e008)

* [Media] Expire a host movie only once its playback stops advancing

Host playback follows the guest's own Bink decode and audio clock, so on
a slow host a movie plays slower than real time. The watchdog fired at
the movie's duration plus a minute regardless, marked the file timed out
and forced EOF on the guest's reads while its decoder was still
mid-stream: Demon's Souls' 171 s attract movie froze on its last
host frame for good. The watchdog now re-arms while frames keep
advancing and expires a movie only after a minute without progress.

(cherry picked from commit daad0f097d0c6369097aeef32b55c9f2d171110a)

* [CLI] Preserve the managed entry point when restarting under Rosetta
2026-10-07 11:02:17 +02:00
kuba a0fd9dcb83
[GPU] Restore half-float arithmetic and image readback state (#1024)
* [Gpu] Cover the whole tile plan when a buffer reads back an image

TrySynchronizeBufferFromImage sized the copy from the mip layout, but the
tile plan of a fully fitting image can extend past it; Silent Hill hit a
128x128 slice planned at the exact end of the mip chain and the tiler
aborted the process. Grow the copy to the plan's tiled end when the
buffer holds it, otherwise keep the guest bytes.

* [SpirvTranslator] Read half-selected V_FMA_MIX literals as f16

op_sel_hi marks a V_FMA_MIX operand as f16 for literals too, but literals
were always read as f32 bit patterns. Silent Hill's deferred lighting
weights a luminance with the f16 literals 0x34CD/0x38B8/0x2F0A (0.30, 0.59,
0.11); as f32 denormals they made the luminance zero, the shader clamped it
to 1e-4 and divided by it, and the title-menu scene came out thousands of
times too bright, which auto exposure then turned black.

* [Gpu] Materialize every fixed DCC clear code on a sampled image

A DCC fast clear stays pending until the surface binds as a colour target;
when a shader samples the surface first, only the clear-to-zero code was
materialized. The other fixed codes (alpha 1, rgb 1, rgba 1) carry their
own colour too. Silent Hill fast-clears UE's separate-translucency target
to (0,0,0,1) and only samples it, so the post composite read stale zeros
and the whole title-menu scene came out black.

* [SpirvTranslator] Keep wave64 LDS phase barriers when a half-mask plan applies

The half-mask plan's barriers order its own mask exchanges, not the
program's shared-memory traffic, yet planning a program switched the LDS
phase ordering off. UE's FFT bloom (wave64, 512 threads, LDS butterflies)
then read half-written rows: Silent Hill's convolution output collapsed
into a flat haze (max 56 for a scene peaking above 1500) and the histogram
fed by it never adapted exposure.

* [Gpu] Publish linear GPU-written images to guest memory by default

Unreal reads its eye-adaptation result back on the CPU through a linear
staging texture (FRHIGPUTextureReadback) and derives View.PreExposure from
it. The image cache was built with linear readback disabled, so the CPU
always read zeros, PreExposure stayed 1.0 and the scene rendered without
pre-exposure. FFT bloom's bright-pixel prefilter, which works in
pre-exposed space, then flattened every pixel to its max luma and the
Silent Hill title menu came out nearly black. SHARPEMU_READBACK_LINEAR_IMAGES=0
restores the old behaviour.

* [Tests] Enable MoltenVK portability devices in headless harness

* [SpirvTranslator] Saturate V_CVT_PKRTZ_F16_F32 at 65504 instead of overflowing to infinity

Rounding toward zero never produces infinity from a finite value: past the
f16 range the result is +-65504. We truncated the mantissa and let
packHalf2x16 round, so large values became infinite. Silent Hill's deferred
lighting packs title-menu values past 65504; its height fog then multiplies
scene color by a tiny transmittance, which keeps 65504 finite but leaves an
infinity infinite, a later pass turns it into NaN and the whole 3D menu
background renders black. Subnormal results now also keep whole 2^-24 steps.
A MoltenVK device test covers overflow, truncation, subnormals, NaN and inf.

* [Tests] Wait for the blocked worker before publishing its signal
2026-10-07 10:59:57 +02:00
kuba 4e6d1e0d9a
[HLE/Cpu] Remove host lock contention from POSIX memory queries, thread resumes and timed waits (#1031)
* [HLE] Answer POSIX host memory queries without the mapping lock

Every HLE import that reads stack arguments queries the guest stack's
protection first. On POSIX the query took the same lock Protect holds
across its mprotect call, and GPU write tracking protects pages
constantly, so each query waited tens of microseconds; Silent Hill: The
Short Message spent up to a second of every five seconds in queries.

Regions are now also published as an immutable snapshot (replaced under
the lock when a region is added or removed), and a query of untracked
memory or of a region without per-page overrides is answered from it
without the lock. Regions with overrides keep the locked path, which now
finds where a protection run ends through an ordered set of overridden
pages instead of visiting every override (write tracking leaves tens of
thousands), and the next region by binary search. Query time drops from
200-1000 ms to 5-50 ms per 5 s.

This is the POSIX counterpart of replacing page-by-page VirtualQuery
scans on Windows.

(cherry picked from commit b6ffe31f28fa93842726b71315c7731f97b5fda8)

* [Cpu] Sleep through nanosleep, resumed on EINTR, in the POSIX Sleep stub

The POSIX stand-in for kernel32!Sleep (which the native sceKernelUsleep
intrinsic calls with milliseconds) converted to microseconds and called
usleep. macOS rejects usleep(>= 1 s) with EINVAL and returns at once, so
every guest sleep of a second or more came back immediately; and a
signal (the runtime's thread activations, for one) ended any sleep early
through an error the stub never looked at.

The stub now builds a timespec and calls nanosleep, and when nanosleep
returns EINTR it resumes with the remaining time. A test exercises the
stub with the Win64 argument register for both a 1.2 s and a 20 ms
sleep.

(cherry picked from commit 43b770f86b5e3aa2332121f1bc2ddf2acc9d2968)

* [HLE] Query POSIX view regions from a lock-free snapshot

Every HLE import first queries the guest stack's protection, and the
view-region query took the same gate the GPU write tracker holds across
its mprotect calls, so each import waited on page-protection traffic
from other threads (the main guest thread spent ~2% of its time in that
wait at Silent Hill: The Short Message's menu).

The region list is now also published as an array snapshot whenever it
changes, and queries read the snapshot without the gate. Per-page
protections already changed in place and were read racily; nothing
changes there.

(cherry picked from commit d7e72cb4974388883696516420b2e9d462778715)

* [Cpu] Skip the scheduler gate when a host thread re-registers the same guest context

scePthreadSelf on a guest thread the scheduler does not own registers
the thread's context on every call, and that took the scheduler-wide
gate each time - tens of thousands of times a second on Silent Hill:
The Short Message's main thread, contending with the dispatcher and
every blocked-thread wake.

Each host thread remembers the handle and context it registered last;
a repeat registration only refreshes the external-handle hint and
returns. New or changed registrations still take the gate.

(cherry picked from commit d1991b2b75261cd1f1ccb4e005b10805f0da24c1)

* [Cpu] Keep each thread's guest continuation stub instead of mapping one per resume

Every resume of a blocked guest thread allocated a 512-byte executable
stub page and a host-RSP slot, and released both when the thread blocked
again: an mmap/munmap pair plus two acquisitions of the host-memory gate
per resume, which the GPU write tracker holds across its own protection
changes. Contended on that gate, resumes were 62% of all lock waiting in
Silent Hill: The Short Message's menu.

Each host thread now keeps a stub page and slot per nesting depth for its
lifetime; a resume reopens the page for writing with mprotect directly
(the page is emulator-private, so it bypasses the tracked host-memory
layer), re-emits the stub and seals it again. Lock waiting across threads
halves (13.6 s to 6.5 s per 30 s).

(cherry picked from commit 2c2293abdd5d19dd1be3d6941dcedf9b482c6420)

* [Kernel] Round host condvar waits up to whole milliseconds

Monitor.Wait truncates its timeout to milliseconds, so a timed wait with
less than 1 ms left became a zero timeout and spun until the deadline.
UE's game thread waits for the render fence in 1 ms slices, which kept a
host core busy for the whole wait and contended the condvar lock with the
signaling threads. Timed waits may wake late, so round up instead.
SH menu 4.29 -> 4.64 fps together with the readback retry change.

(cherry picked from commit 66eaa0095fe594ff8e285cbf31c32bd84274ac85)

* [Tests] Run the POSIX Sleep stub test only in x64 processes

The stub is x86-64 machine code; a native arm64 test host cannot map or run
it, so the macOS arm64 CI runner failed to allocate the stub page.
2026-10-07 10:56:03 +02:00
kuba d809f84491
[SpirvTranslator] Share one EXEC test across a run of vector ALU writes (#1040)
A vector register write is modelled as select(EXEC, result, old value), so the
old value of every register the shader writes stays live across the write. That
guard is the translator's largest per-instruction cost: dropping it altogether
(wrong results) takes Silent Hill's volumetric-fog compute from 13.43 to 10.64
ms, and the exec-full analysis can only prove 194 of its 875 instructions run
with every lane set.

A run of instructions whose only effect is their vector destination can instead
run inside one if (EXEC). The masked-off lanes skip the whole run, which is what
the hardware does to them anyway, and only the join needs the old values. A run
stops at anything the wave runs even where this lane is masked off: SALU is not
EXEC masked and every invocation keeps its own copy of the scalar registers, a
compare writes VCC or EXEC (GFX10 keeps that destination in the instruction's
control, not in its destination list), a cross-lane read needs its neighbours to
have run, and LDS, memory and the DPP encodings reach outside the register. Six
instructions is where the branch starts paying for itself.

Compute only: the same grouping made the deferred lighting pixel program 28%
slower (11.03 -> 14.11 ms per scope), where a wave already runs with helper
lanes. SHARPEMU_EXEC_RUN=0 turns it off, SHARPEMU_EXEC_RUN_MIN sets the length.

Silent Hill title menu, same build, SHARPEMU_EXEC_RUN=0 vs on:
  offline replay min ms   fog D5DF9DC46C4E35EA  13.42 -> 12.21 (-9.0%)
                          FFT 674E5A7163897BC9  16.37..17.38 -> 17.06 (flat)
                          NGG B482CD3A01A37F0F   0.494 ->  0.492 (unchanged)
  in-game ms per dispatch fog D5DF9DC46C4E35EA  16.59 -> 15.34 (-7.5%)
                          FFT 674E5A7163897BC9  13.81 -> 13.77
                              2BFB24830D8FCFAA   4.78 ->  4.58 (-4%)
  in-game ms per scope    848AFAD7/9D180B8A     11.03 -> 11.36 (unchanged SPIR-V)
                          F987C1A4/379BE850      1.90 ->  1.72 (unchanged SPIR-V)

spirv-val passes on the fog, FFT and NGG modules; the menu image is unchanged
with Anita present.
2026-10-07 10:52:01 +02:00
kuba da0953845b
[SpirvTranslator/Vk] Cheaper guest buffer loads and f16 conversion, gated on device probes (#1035)
* [SpirvTranslator] Load dword-aligned 32-bit formatted buffer components as words

A formatted untyped buffer load decodes the descriptor format at run time,
reading every component byte by byte through the generic layout select
chain. For dword-aligned 32-bit data formats (32, 32_32, 32_32_32,
32_32_32_32) with a raw-bit number format (UINT, SINT, FLOAT) a component is
one buffer word; that branch loads it directly and applies the same swizzle
and bounds rules. The descriptor is uniform, so the branch does not diverge.
UE GPU-skinning vertex shaders fetch bone data this way; Silent Hill: The
Short Message's menu goes from 1.3 to 2.0 FPS.

(cherry picked from commit 20540cd153855964d817daf065de3e243fd547bd)

* [SpirvTranslator] Convert f16 with the native pack/unpack when the host measured it exact

Every packed-f16 (VOP3P) lane widens its operands to f32 and rounds the
result back, and both conversions were the branchless integer sequences in
EmitHalfToFloat / EmitFloatToHalf: about twenty scalar ops each, because
GLSL UnpackHalf2x16 / PackHalf2x16 have no guaranteed rounding or subnormal
behaviour without float-controls execution modes. A device capability bit
does not settle it either - MoltenVK on Apple silicon reports
shaderRoundingModeRTEFloat16 and shaderSignedZeroInfNanPreserveFloat16 yet
not shaderDenormPreserveFloat16 - so only a measurement can.

ShaderCompileRequest.NativeHalfConversionExact, which the host sets only
after measuring the two ext instructions against these sequences on the
running device, swaps both helpers for the single ext instruction the
driver lowers to one hardware convert. It defaults to false, so an
unmeasured device keeps the exact emulation.

Silent Hill f2 volumetric fog dispatch: 30.7 -> 21.9 ms per dispatch in
replay, output unchanged.

(cherry picked from commit 10f76eeac0d4306172e41ecff86b737f6a3c9634)
(cherry picked from commit 7f18cc96ae58ac5fd47da6562c4ba3abe22ccb4a)
(cherry picked from commit 972f658033f8339effe42c5d305af87bcbab93f0)

* [Vk] Probe f16 conversion at device setup and report the verdict

A one-time compute pass at device setup measures the device's GLSL
UnpackHalf2x16 / PackHalf2x16 against the translator's own f16 conversion
before any guest shader is compiled, and only a clean measurement lets the
translator use them (ShaderCompileRequest.NativeHalfConversionExact). The
vectors cover all 65536 f16 bit patterns, every f16 value widened to f32,
the midpoint between adjacent f16 values and that midpoint one f32 ulp
either way, the overflow edge, signed zeroes, infinities, NaNs and f32
subnormals, and each is measured in both directions: 643200 comparisons.

Every finite value, zero and infinity must be bit-exact, sign included. A
NaN only has to stay a NaN, because neither side defines its payload: the
emulation picks sign | 0x7C00 | 0x200 narrowing and carries the f16 payload
widening, while the measured hardware convert canonicalizes to a positive
quiet NaN. On an Apple M4 that is the only disagreement - 2314 of 643200,
every one a negative NaN whose sign the hardware cleared - and f16
subnormals convert exactly despite shaderDenormPreserveFloat16 being false.

The probe never fails device setup: any error leaves the exact emulation in
place and says so on the reported line. SHARPEMU_NATIVE_HALF=0 forces the
emulation, =1 takes native without measuring. The result is one line:
  [VK][F16] native half conversion exact=True mismatches=0 tested=643200

The flag reaches the translator through IShaderPipelineHost, so it is
process-constant and cannot mix two translations of one program; the saved
driver pipeline cache keys its entries by the module it was given, and the
Metal host does not probe and keeps the emulation. Offline replays run the
same probe, so a case translates the way the game would.

(cherry picked from commit 6a343683d890b4c6d123c84fdacb41e718ec4c19)
(cherry picked from commit 65ca663aa2bfb1fcc69709c73ab6189b07ead3c1)
(cherry picked from commit 003b1216bd311e5c5fb1d48ca01a66efa3fc51de)

* [SpirvTranslator] Read an unaligned buffer word as a funnel shift of two words

The byte-wise decode of a formatted buffer load read each byte of a component
from its own bounds-checked word load: four loads, four range tests and a byte
assembly for a value that spans at most two words. One funnel shift of those
two words is the same value, including out of range, where a word reads zero on
both paths and so contributes zero bytes. Every sub-dword buffer load goes
through the same helper.

The decode is the branch a formatted load takes when its address is not dword
aligned, so its size also sets the register pressure of the aligned branch next
to it. Silent Hill: The Short Message's volumetric fog dispatch
(0xD5DF9DC46C4E35EA, 8 formatted loads in its light loop) goes from 8.68 to
7.28 ms in offline replay, and the module from 394 to 360 KiB. An experiment
that dropped the byte-wise branch entirely measured 7.35 ms, so the funnel
shift is worth all of what the branch cost.

(cherry picked from commit 0c996ffab38144d795517e68cb2ca9d8d48e8988)

* [SpirvTranslator] Load a guest buffer word unchecked where the device zeroes out-of-range reads

Every guest buffer word is read through a range test, an address clamp and a
zero select: three operations whose only purpose is to produce the zero the
hardware returns past the end of a V#. A device with robustBufferAccess2 that
honours it returns that zero itself, so the three are pure overhead there -
dropping them measured about 12% of Silent Hill's volumetric fog dispatch, 482
checked words in one program.

ShaderCompileRequest.ZeroOutOfBoundsBufferReads turns them off and defaults to
false: an out-of-range read is undefined without the promise, so only a host
that measured the device may set it. It is set from a device probe, never from
a capability bit, because MoltenVK runs on Metal, which has no hardware bounds
checking.

(cherry picked from commit 2ba626a0ac7157f93f348cfe7573ff1092762d8c)

* [Vk] Probe out-of-range buffer reads at device setup and report the verdict

A one-time compute pass binds 1 KiB of a 4 KiB allocation that carries a
sentinel everywhere and reads all 4 KiB back through the descriptor: the words
inside the range must still read their sentinel and the words past it must read
zero. Only a clean measurement lets the translator drop the range test, address
clamp and zero select it puts around every guest buffer word
(ShaderCompileRequest.ZeroOutOfBoundsBufferReads).

The probe only runs where the device enabled robustBufferAccess2, because an
out-of-range read is undefined without it and can fault the device; everywhere
else it reports the reason and the checks stay. On this Apple M4 through
MoltenVK the feature is not supported at all, so nothing changes:
  [VK][OOB] out-of-range buffer reads zero=False mismatches=unprobed tested=0
      note=robustBufferAccess2 is not enabled on this device

SHARPEMU_ZERO_OOB_READS=0 keeps the checks, =1 drops them without measuring.
The flag reaches the translator through IShaderPipelineHost, so it is
process-constant and cannot mix two translations of one program.

(cherry picked from commit e81d924349042acc1122a66d4c767268bd6ef2a4)
2026-10-07 10:51:57 +02:00
kuba db32c9d882
[SpirvTranslator] Cut emulated-wave64 and private-LDS overhead in translated shaders (#1034)
* [SpirvTranslator] Keep pure scalar lane spills in private slots under emulated wave64

A wave64 program run as a 64-thread workgroup on a 32-lane host emulates
v_readlane with an LDS exchange and a workgroup barrier. Compilers use
constant-lane v_writelane/v_readlane pairs on a VGPR as SGPR spill slots;
when that VGPR is written only by constant-lane writelanes and read only by
constant-lane readlanes, each (vgpr, lane) pair is a private scalar, so the
readlane loads the slot instead of exchanging through LDS. This halves the
heaviest compute dispatch in Silent Hill: The Short Message's menu.

(cherry picked from commit 9915b88e68b6b69d6b74ea931a22eb0589c56f1a)

* [SpirvTranslator] Zero private LDS lazily through a written-dword bitmap

Graphics stages model LDS as a per-invocation private array that must
read zero where the invocation has not written. The array carried a zero
initializer, but Metal keeps a dynamically indexed private array in stack
memory, so every invocation cleared all of it: an NGG vertex shader (the
PS5 default, with in-shader culling through LDS) cleared 8 KiB per vertex.

The array is now uninitialized and a zero-initialized bitmap of written
dwords (1/32 of the size) records which slots were addressed; LdsPointer
zeroes a slot the first time it is addressed, so loads, stores and atomics
keep the zero-read semantics. Compute LDS stays workgroup memory.
Silent Hill: The Short Message's menu, dominated by ~45M shadow-pass
vertices per frame, goes from about 2.0 to 3.1 FPS.

(cherry picked from commit 5738b8574397cf2be08cd4e1518b33057c8867b5)

* [SpirvTranslator] Test the lane's mask bit in one register under emulated wave64

VCC and EXEC keep a per-lane boolean that every mask write refreshes, and the
refresh composed the 64-bit mask from its two registers, built a 64-bit lane
bit and masked them. A host without 64-bit integer arithmetic (Apple GPUs
through MoltenVK) emulates each of those with a pair of 32-bit operations. The
bit lives in exactly one of the two registers, so selecting that register and
shifting inside it is the same test in 32-bit arithmetic.

Only the emulated-wave64 path changes; wave32 already tested one register, and
a native wave64 host keeps the existing form, which also clears the bit for
lanes outside the guest wave.

(cherry picked from commit 1b2651047fdf232304142c82168e487244dda4ef)

* [SpirvTranslator] Let s_barrier publish only what the guest waited for

Every compute s_barrier became an OpControlBarrier with AcquireRelease
over uniform, workgroup and image memory, on the assumption that the
guest had drained vector memory first. s_barrier only orders execution;
what it publishes is whatever the preceding s_waitcnt drained. A barrier
that follows an LDS-only wait (lgkmcnt(0)) publishes LDS, and ordering
device memory there costs a cache flush the guest never asked for: UE's
FFT bloom convolution barriers 48 times per group, all LDS-only.

The translator now tracks, per block, whether any wait drained vector
memory - SOPP vmcnt(0), or the GFX10 SOPK vscnt(0)/vmcnt(0) forms, since
stores are counted by vscnt there - and a barrier after an LDS-only wait
carries workgroup memory only. A drained counter stays drained for the
rest of the block, and a barrier with no wait in its block keeps the
full semantics (the wait may be in a block this one cannot be ordered
against).

(cherry picked from commit 1f81df59bc07d05f2baa6283da95f4901dada444)
2026-10-07 10:51:52 +02:00
kuba 30321142cb
[GPU/Vk] Keep guest readbacks of GPU-written memory off the command worker (#1032)
* [Vk] Run async readbacks on a second general queue family when no dedicated one exists

The async readback queue was only taken from a family without graphics,
so drivers that expose several general families (each its own hardware
queue) kept every guest readback on the main queue and the command
worker. Any other family with transfer support now qualifies after the
dedicated transfer and compute families.

(cherry picked from commit 7b04d6185dfc1711f0fbdf5c75c842a065acd1fa)

* [GPU] Let guest reads of GPU-written memory wait on the main queue off the worker

A guest thread reading memory the GPU wrote hands the download to the
command worker, which recorded the copies, submitted and then waited for
the whole GPU before handing the bytes back - unless a dedicated readback
queue existed, where the download ran asynchronously and only the guest
thread waited. MoltenVK exposes one queue family in-process, so on macOS
every such read idled the worker for tens of milliseconds, several times
per frame in Silent Hill: The Short Message's menu (a quarter of the
worker's time).

Without a readback queue the worker now copies the pieces into a buffer
of their own, submits without waiting and returns a pending download
carrying the submission tick; the guest thread waits for that tick on the
timeline (safe from any thread) and completes the read back on the
worker, as the readback-queue path does. The worker's GPU wait time drops
to zero; SHARPEMU_MAIN_QUEUE_PENDING_READS=0 restores the synchronous
path.

(cherry picked from commit 6c9ad44bcea7f9396a7564621fcbda3841834052)

* [GPU] Re-issue a stale pending readback instead of reading synchronously on the worker

A guest read of GPU-written memory records a copy and waits for its tick
off the queue. When another GPU write lands first, the completion fell
back to a synchronous read on the command worker, which stalled it until
the GPU drained (up to half of SH's readbacks). The guest thread now
re-issues the pending read and waits again; only the fourth attempt falls
back to the synchronous read.

(cherry picked from commit 17bf5bb958ebfd4dd980dbf241cbe9e77fffd938)
2026-10-07 10:51:48 +02:00
kuba 1e784a035f
[SpirvTranslator] Keep the packed-half vector registers in one variable per register (#1041)
The f16 fast path shadowed the whole vector register file with a 512-entry
private array of vec2 and zero-initialised it, even though every access uses a
constant register number. That is the array shape Metal keeps in thread memory
instead of registers - the same trap V_MOVREL's dynamically indexed register
file hit (Octopath's instanced vertex shader, 112 -> 6.4 ms/draw) - and it also
left AMD with an unused 4 KiB .bss global that broke two-stage links. One
private variable per register, declared on first use, removes it.

308 of the 1019 shaders Silent Hill's title menu translates used the array,
including the two hottest pixel programs. The generated Metal for the
volumetric-fog compute D5DF9DC46C4E35EA drops from 282 KB to 269 KB and no
longer declares a 4 KiB thread array. Measured GPU time on the menu is
unchanged within run-to-run noise (fog 18.2/19.9 -> 20.1 ms per dispatch,
pixel 934F121D8F666572 0.048/0.061 -> 0.041 ms per scope), so this is a
code-shape fix that removes the spill risk rather than a measured win.
2026-10-07 10:49:01 +02:00
kuba 7ab6de1b93
[GPU] Cut per-draw command-worker cost in resource materialization and pixel input setup (#1039)
* [ShaderCompiler] Materialize directly for plans whose cached inputs never repeat

The materialization cache records every guest word a draw reads and keys
the result on the draw's user data. Most Silent Hill draws point their
user data at per-draw constants, so only 8% of lookups hit and every miss
still paid for recording the reads and storing an entry. A plan now
counts its lookups and hits; after 64 lookups with fewer than one hit in
eight it walks its resources directly and probes the cache again on every
64th draw. On the SH title menu the command worker's busy time per draw
fell from ~125 to ~111 us (cache hit rate of the remaining lookups 70%).

* [GPU] Scan a pixel program's interpolated attributes once per decoded program

Every draw scanned all instructions of its pixel program twice, once
through a LINQ chain with Distinct/Order/ToArray, to count interpolated
attributes and the vertex outputs they read. The sorted attribute set
is a property of the decoded program, so it is computed once and kept
beside it. Pixel input resolution on the SH menu dropped from ~14 us to
a few us per draw.
2026-10-07 10:48:57 +02:00
kuba 70dcbe4e05
[GPU] Keep sampled depth attachments in one rendering scope (#1037)
Draws that sample the depth attachment need its read-only layout; every
other draw got the writable layout, even one that only tests depth. A run
of depth-sampling particles between test-only draws flipped the layout on
every draw, and each flip ended the rendering scope. Image state tracking
also recorded a barrier whenever the access changed, even from one read
to another in the same layout.

A draw that neither samples nor writes the attachment now keeps the
read-only layout it is already in, and reads after reads in one layout
record no barrier: the tracked state accumulates every reader, so the next
writer still waits for all of them. Depth-transition scope breaks in
Silent Hill: The Short Message's menu drop from ~1250 to ~820 per 5 s.

(cherry picked from commit 5563417d72fadefb115b300291b1e019b3171466)
2026-10-07 10:48:52 +02:00
kuba 0aa611e317
[GPU] Draw non-indexed indirect draws from their arguments on the GPU (#1036)
Indexed indirect draws already let vkCmdDrawIndexedIndirect read their
counts, but a non-indexed DRAW_INDIRECT read its four arguments on the
CPU. When a compute pass had just written them (UE writes rectangle-list
draw arguments this way every frame), the read downloaded the buffer and
waited for the whole GPU: about one 20-50 ms stall per frame in Silent
Hill: The Short Message's menu.

The interpreter now hands the argument address to the host when it draws
non-indexed indirect draws on the GPU (deferring the instance count read
as the indexed path does), and the executor records vkCmdDrawIndirect.
The guest layout (vertexCount, instanceCount, firstVertex, firstInstance)
is VkDrawIndirectCommand. Rectangle lists use the general rectangle-list
variant, since the count is unknown; fans, polygons, legacy lists and
targetless draws (which may be retained and replayed) still read the
arguments on the CPU. SHARPEMU_CPU_INDIRECT_DRAW=1 keeps the CPU path.

(cherry picked from commit f2b91befb7dd27d65a35546f1e57dc88f04a5c82)
2026-10-07 10:48:47 +02:00
kuba 435bbd4844
[Cpu] Copy page-sized guest memcpys on the managed path (#1055)
The native memcpy fast path copies with rep movsb straight into guest
memory. Pages the GPU reads are write-protected so CPU writes can be
tracked, so a copy into them takes one protection fault per page, and
under Rosetta each fault is a signal round trip of about 0.2 ms. The
managed memcpy marks the whole destination written before it copies and
takes no faults. Copies of at least 4 KiB now leave the stub for the
managed export; smaller ones keep the native copy, where one import
transition would cost more than the copy. SHARPEMU_MEMCPY_MANAGED_MIN
overrides the threshold.

Demon's Souls, 230 s through the PlayStation Studios intro: 536k
write-tracking faults become 71k, and the intro presents about a fifth
more frames.
2026-10-07 10:48:00 +02:00
ParantezTech 3e2ad63303 [readme] New screenshots v2 2026-10-06 19:07:24 +03:00
ParantezTech ac8608449f [readme] New screenshots 2026-10-06 19:07:06 +03:00
Berk 2df6f5b0a0
Unity fixes 1016p1 (#1043)
* [HLE] Let schedulers report guest thread stack bounds

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Core] Report the mapped stack of each guest thread

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Validate pthread stack bounds before reporting them

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Report every guest thread's stack in pthread attributes

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Publish semaphore handles as 64-bit values

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Accept zero-count semaphore signals

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Route semaphore waits through one core

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Poll host semaphore waits and deliver guest exceptions

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Add scePthreadSemTimedwait

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Remove every pending copy of a deleted event

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Block timed event queue waits in the guest scheduler

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Refresh pending user data when an event is re-added

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Keep every end-of-pipe interrupt event

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Track deadlines and POSIX results on sync waiters

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Poll host sync waits in bounded slices

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Share the sync-on-address wait and wake cores

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Kernel] Add _umtx_op wait and wake

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Np] Track WebApi2 user contexts and push filters

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Np] Add sceNpWebApi2PushEventDeleteHandle

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Np] Add sceNpWebApi2PushEventRegisterCallback

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Tests] Cover kernel sync, pthread stack bounds and NpWebApi2

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Accept HTile-backed compressed stencil targets

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Tests] Cover HTile-backed compressed stencil targets

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Accept stencil targets with or without HTile backing

* [Tests] Cover stencil compression with and without HTile

* [ShaderCompiler] Treat V_CMPX as an EXEC write in every encoding

* [Tests] Cover SDWA V_CMPX in the EXEC-full analysis

* [GPU] Give images first found without metadata the DCC metadata of a texture request

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Tests] Cover DCC metadata adopted from a texture request

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Number command stream submissions in admission order

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Queue control barriers behind accepted command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Cancel pending control barriers when the command stream fails

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Cancel pending control barriers when the command stream is discarded

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Run relay work after accepted command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [VideoOut] Order relay work behind the presenter command stream

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [GPU] Let backends run work after pending command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [VideoOut] Run state changes after pending command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Metal] Run state changes after pending command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [VideoOut] Close ports after pending command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [VideoOut] Unregister buffers after pending command streams

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

* [Tests] Cover ordered video-out state changes

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>

---------

Co-authored-by: Sekai <140012992+igettingit@users.noreply.github.com>
2026-10-06 18:43:21 +03:00
Berk a17aaca533
Astro playroom shaders (#1030)
* [Vulkan] Enable shader clip and cull distances

* [Vulkan] Track shader clip distance support

* [ShaderCompiler] Add a clip distance support flag to compile requests

* [GPU] Expose host clip distance support to pipelines

* [GPU] Pass clip distance support to shader compilation

* [ShaderCompiler] Reserve a clip plane for position exports

* [ShaderCompiler] Cull primitives with a zero position

* [GPU] Bind vertex buffers with their guest descriptor sizes

* [GPU] Accept B10G11R11 float vertex attributes

* [GPU] Spill oversized image readbacks to a temporary buffer

* [GPU] Carry DCC metadata on compressed textures

* [GPU] Mark sampled DCC clears through the metadata fill path

* [Tests] Cover vertex descriptor bounds and oversized image readbacks

* [GPU] Revert binding vertex buffers with their guest descriptor sizes

* [GPU] Carry DCC metadata only on single-layer 2D textures

* [Tests] Cover DCC metadata on 2D, 3D and array textures
2026-10-06 01:32:13 +03:00
ParantezTech 83abe47b6e [readme] re-order 2026-10-05 16:29:03 +03:00
ParantezTech d6c4778218 [readme] added warning for not official sites, donations etc. 2026-10-05 16:27:41 +03:00
ParantezTech 5965b07c7b [Logging] Skip "tbb_thead" without LogThreadMode 2026-10-05 16:18:27 +03:00
ParantezTech 4a822aedb9 Merge branch 'main' of https://github.com/sharpemu/sharpemu 2026-10-05 15:36:18 +03:00
ParantezTech 22bbcb1415 [readme] update screenshot 2026-10-05 15:36:01 +03:00
T 9e99769ce5
[GPU] Report mip statistics for sampled textures so streamed textures reach full detail (#1029) 2026-10-05 14:39:40 +03:00
Berk 41a1912cd9
[SRT] Compile shader resource plans in the background (#1028)
Each shader resource plan is compiled once to a DynamicMethod that evaluates
its resource table graph with plan-local value slots instead of the
interpreter's hashed cache. ASTRO's PLAYROOM goes from about 20 to 60 fps.

Compilation runs on a low-priority "SRT compiler" thread; until a plan is
ready, the interpreter evaluates it, so a new shader no longer stalls the
render thread while its plan is JIT-compiled. A plan whose compilation fails
stays on the interpreter. SHARPEMU_SRT_NATIVE=0 turns the compiled path off;
it is also off when the runtime does not support dynamic code.
2026-10-05 01:19:33 +03:00
Berk 0163750e7e
Page fixes (#1023)
* [DeS] Fixes for page faults and stack bounds issues in the emulator and audio fixes

* [ShaderPrewarm] Hold the game until the prewarm finishes and resume interrupted runs

The prewarm compiled thousands of compute pipelines on background threads
while the now faster boot ran beside it, so logos, Bink movies and the first
scenes raced the compile and dropped frames.

- Hold the guest at its first splash hide, GPU submission or CPU flip until
  the prewarm is decided and done; the render thread keeps presenting the
  splash. SHARPEMU_SHADER_PREWARM_WAIT=0 opts out.
- Stamp only the shader translators, the compiler type and the driver, so a
  Libs-only build no longer triggers a full prewarm.
- Record finished pipelines in shader-prewarm.progress so an interrupted
  prewarm resumes with the remaining ones.

* [AudioOut2] Block a blocking push only until a queue slot frees

A blocking sceAudioOut2ContextPush waited only when the host stream hit its
128 KiB cap, so a title rendering faster than real time kept about 680 ms
queued and every sound played that far behind (GTA V: queue=2 context,
queued_ms avg=678). The push now waits until the device holds the cushion
plus QueueDepth-1 grains, the level GetQueueLevel already reports as full;
the host cap stays as the limit for non-blocking bursts. GTA V now holds
about 41 ms with no underruns.

* [GPU] Run bounded modulo copies of plain words on the host

Demon's Souls copies its per-frame constant and descriptor tables with a
compute kernel (dst[i] = src[i % N] for i < count). Run on the GPU, the
destinations stay GPU-dirty, and every draw whose resource tables read them
waits for a readback: about 19% of the render thread in the title scene,
for values that never changed.

The kernel is now recognized by its instruction sequence. When both
descriptors are plain 32-bit words of the same format and neither range is
GPU-dirty or GPU image memory, the copy is written to guest memory through
the host DMA path and the dispatch is skipped; anything else still runs on
the GPU. SHARPEMU_HOST_BOUNDED_COPY=0 turns it off.

Title scene with profiling: 7.4-8.6 -> 11.8-15.9 fps.

* [Diagnostics] Summarize synchronized table reads and trace several writer addresses

SHARPEMU_TRACE_GPU_READS=1 now also reports, every five seconds, the guest
words resource planning read through a GPU synchronization: read count, how
often the value changed, and the first and last value. SHARPEMU_TRACE_WRITER_ADDRESS
accepts a comma-separated list.
2026-10-04 19:07:37 +03:00
Berk 57e0da2150
Revert "[DeS] Fixes for page faults and stack bounds issues in the emulator a…" (#1022)
This reverts commit ec0198f2d0.
2026-10-04 05:57:24 +03:00
kuba cb42e849d7
[VideoOut] Keep guests on SDR output under Auto HDR on macOS (#1020)
Upstream e7a4f0a0 started reporting HDR to the guest whenever the display
has HDR enabled. On an HDR Mac, Silent Hill switches its output to HDR,
a guest pipeline then fails to compile in MoltenVK (ushort4 output to a
BGRA8 attachment) and the process crashes inside MoltenVK on every run.
Auto now stays SDR on macOS; --hdr=on still opts in.
2026-10-04 05:39:24 +03:00
Berk ec0198f2d0
[DeS] Fixes for page faults and stack bounds issues in the emulator and audio fixes (#1021) 2026-10-04 05:38:49 +03:00
ParantezTech 8903e3760b [readme] update screenshot 2026-10-04 04:28:03 +03:00
T d4891229e9
[SpirvTranslator] Shader fixes (#1019)
* [ShaderCompiler] Fix packed 10 and 11 bit buffer format layouts

* [SpirvTranslator] Pass W as the pixel position input instead of its reciprocal

* [SpirvTranslator] Keep lane spills in per invocation slots for all 64 lanes

* [SpirvTranslator] Match the hardware float conversion and NaN rules

* [SpirvTranslator] Apply VOP3 sign modifiers to conditional mask sources

* [GPU] Download guest DCC metadata before a known target is sampled

* [ShaderCompiler] End bit scan image tables at a sampler loaded from the same base

* [ShaderCompiler] Treat image table candidates with unsupported formats as null
2026-10-04 01:17:02 +03:00
Berk 6fe8b87f48
chore: bump version to 0.0.5-nexus (#1018) 2026-10-03 05:15:35 +03:00
ParantezTech 375d434353 [readme] update game order and screenshot 2026-10-03 05:13:13 +03:00
Berk 0c616d80ff
[Font] Fix font face creation (#1010) 2026-10-03 05:04:56 +03:00