Commit Graph

681 Commits

Author SHA1 Message Date
kuba d994ff4e34 [ShaderCompiler] Persist versioned scalar analysis across launches 2026-10-01 18:29:09 +02:00
kuba 99a19fa2fa [ShaderCompiler] Intern scalar graphs without string keys or hit allocations 2026-10-01 18:28:48 +02:00
kuba 9c03cb0b0b [Cpu] sceKernelWaitSema is an import-loop guard boundary
A thread that blocks on a semaphore between iterations is waiting, like the
condition-variable waits already on the list. A job-wait loop that runs queued
work between timed semaphore waits was otherwise taken for a hang once loading
outlasted the guard window.
2026-09-30 17:35:00 +02:00
kuba bedf4c44c7 [Kernel] sceKernelAprGetFileSize writes the resolved file size
The export was a success stub that never wrote its out parameter, so callers
sized buffers from uninitialized memory. The signature is (id, uint64_t* size);
it now answers from the APR file registry like sceKernelAprGetFileStat.
2026-09-30 17:35:00 +02:00
kuba 9e1e15cc5c Merge upstream/main (#955) into integration/all-prs
#955 overlaps several open PRs. Resolution:
- GuestPageTracker, GuestBufferCache, ShaderIdentity, SharedBackingViews: upstream's versions
  (they carry the same allocation-free invalidation, hashing and lock-free reads as #944/#968).
- RELEASE_MEM: upstream's deferred release flush (supersedes #966).
- CommandStreamQueue.Done: ours (#941 queued frame boundary; upstream only reformatted).
- Flip snapshot pool: ours (locked; snapshots are taken on the command-stream thread and
  retired on the render thread), upstream's unlocked pool dropped.
- Gen5SpirvTranslator: our per-register variables and structurer (#923, #975/#976) first,
  upstream's guarded in-order blocks as the fallback, then the dispatcher; upstream's
  lane-spill slots, bounded move-relative, exec-known-full and PS input sharing kept.
2026-09-30 17:35:00 +02:00
Astell c076513bd6
Astrobot / Demon's soul performance improvement (#955)
* [Gpu] Astro Bot performance: 14 -> ~60 fps at the title scene

- Defer RELEASE_MEM command-buffer flushes instead of submitting per packet
- Resolve indexed indirect draws and dispatches on the GPU
- Async buffer readbacks on a dedicated transfer/compute queue
- Pool image backings, flip snapshots and tiler resources
- One-frame command-stream run-ahead
- Lock-free backed-range and image page-owner checks on CPU writes
- Scalar value cache with generation-stamped reset; memoized invariant phis
- Shader compiler: structured forward-only CFGs with function-scope
  registers, EXEC-full guard elision, bounded V_MOVREL offsets
- Trivial-leaf import dispatch and strchr/strrchr fast paths
- SHARPEMU_GUEST_REFRESH_RATE option

* [Tests] Fix full-suite flaky tests

- Red-zone patcher: when every fixed trampoline candidate is taken, look
  for any free host range within relative-jump reach
  (PhysicalVirtualMemory.EnumerateFreeHostRanges); the test places its
  image in a probed free hole
- Kernel memory tests: probe a free PRT-area address instead of the fixed
  0x1026C00000; the reservation-extent test only rejects picks inside
  the reservation
- Release checks tolerate another thread reusing the freed range
- Allocation tests measure on a dedicated thread and keep the least
  allocating of several rounds (AllocationMeasurement.SteadyState)

* [Gpu] Astro Bot: structured loops, buffer slabs, pad motion

- Shader: emit natural loops as structured SPIR-V loops (OpLoopMerge)
  instead of the block dispatcher, and merge SCC-uniform if/else joins
  as selects so descriptors picked on a branch stay evaluable per draw.
- Shader: decode V_FFBH_I32 and V_MIN3_F16; read the DS GDS bit from
  bit 17 (GFX10) and route GDS append/consume through shared atomics.
- Gpu: sub-allocate small device-local buffers from shared memory slabs.
- Pad: report motion data by default (Astro Bot never imports
  scePadSetMotionSensorState), convert acceleration from m/s^2 to G,
  and add scePadResetOrientation / scePadSetAngularVelocityDeadbandState.

* [CPU] Stop pinning guest threads to host cores by default

Guest affinity packed Demon's Souls' 13 spinning BPE job workers onto 10 host lanes and put its renderer next to them at equal priority, so the renderer and lock holders waited out whole scheduler quanta. Intro 10.6 -> 44.7 fps, menus 11.6 -> 47.5 fps. SHARPEMU_GUEST_AFFINITY=1 restores pinning.

* [Media] Convert host movie frames to YUV on the decoder thread

The render thread converted every decoded Bink frame from BGRA back to YUV 4:2:0 (6.7 ms per frame). The decoder thread now produces the planes and the presenter uploads them as-is. PS Studios logo 33 -> ~50 fps, attract movie 44 -> 60 fps.

* [Agc] Accept a zero destination in sceAgcDcbWriteData

Demon's Souls emits WRITE_DATA with address 0 into a template and patches it after copying. Returning null made the title patch a relocated null pointer, which wrote a stack-derived value into its label and was then parsed as an unknown NOP marker (GPU FATAL).

* [Loader] Patch short red-zone faulting accesses next to branches

A faulting access shorter than a jump could not be relocated when followed by a branch or a branch target, so a handled fault let Windows overwrite the red zone. Spans may now end with a direct branch (run after the stack pointer is restored) or start up to three instructions earlier. Fixes a Demon's Souls crash after the new-game intro movie.

* [GPU] Astro Bot rendering fixes: compute subgroups, DCC clears, PS inputs, texture MIN_LOD

- Compute: pin non-emulated compute pipelines to a 32-lane subgroup
  (VK_EXT_subgroup_size_control) so wave64 groups other than 64
  invocations keep lanes 32..63 active on AMD (striped froxel volume).
- Shader translator: 64-bit AND for the wave32 S_*_SAVEEXEC_B64 mask.
- PS inputs: slots that read one VS parameter share one host input;
  a smooth/flat slot next to a V_INTERP_MOV slot is rebuilt from the
  per-vertex values (black save cards, NaN normals, black props).
- Render targets: drop unwritten color targets of depth passes from both
  the attachments and the pixel outputs, keeping locations aligned.
- DCC: materialize pending zero fast clears before shader access so a
  later attachment bind does not wipe compute writes.
- Textures: honour the T# MIN_LOD with VK_EXT_image_view_min_lod so
  streamed textures never sample unloaded mips (blown-out stadium sky).
- Device: enable VK_KHR_maintenance5 for point lists without PointSize.

* [Audio][GPU] ATRAC9 independent mono streams, BC storage fallback, 32-bit bit counts

- LibAtrac9: decode config header 0x30 streams (PS5 ambisonics), where every
  channel is an independent mono stream interleaved frame by frame.
- Images: when the driver refuses storage usage on a block-compressed image,
  compute writes go through an uncompressed replacement of the same memory.
- SPIR-V: count 64-bit masks with two 32-bit OpBitCount, which Vulkan requires
  without maintenance9.
- Agc: drop the indirect-draw emit debug log; report the draw modifier in the
  unsupported indirect draw error.

* [GPU] Partial texture-pool uploads and cheaper per-draw preparation

- A CPU write into a large layered texture (Demon's Souls' 256-layer BC3
  pools) re-uploaded the whole image, ~750 ms of GPU detiling in one frame.
  Each (mip, layer) piece's guest bytes are hashed at upload; a refresh
  uploads only the pieces that changed.
- Device-address preparation touched and checked every registered buffer for
  each dispatch. Recency touches now run once per retirement tick, and uploads
  only visit buffers in blocks the tracker does not know to be clean; hot
  pages stay dirty, so they are still re-uploaded every time.
- Resource materialization cache: when the only changed words are ones the
  flattened table alone reads (per-frame inline constants), only the table is
  evaluated again.
- A full batch no longer splits an open render pass before 512 draws.
- Lock-free lookups for shader headers, device format properties and the idle
  host movie bridge; the SPIR-V dump toggle is read once per program cache.

* Demon soul - fix texture

* Delete runahead tests

* Screcrow fix for nvidia GPU
2026-09-30 18:14:21 +03:00
kuba 5449fea881 [Gpu] Declare every parameter the pixel program reads in the paired vertex program
A vertex program declares outputs for the parameters it exports plus as many locations as the
pixel program has inputs. SPI_PS_INPUT_CNTL can map a pixel input to any parameter number,
though, so a pixel program with two inputs may read parameters 4 and 5. Metal requires every
fragment input to be written by the vertex stage, so the pipeline failed to link ("fragment
inputs user(locn4), user(locn5) ... not written by vertex shader"), the command stream slice
failed and Silent Hill stopped rendering at a scene change.

The required output count now covers the highest location the pixel program reads, resolved
through the same input mapping its translator uses; missing exports are zero-filled as before.
The pipeline creation error also names the vertex and pixel programs.

(cherry picked from commit 80ec9fb53cfae922e458e2dd43d4b1010dbd2701)
2026-09-30 15:26:49 +02:00
kuba 70d1d2f443 [Cpu] Stop guest threads at their next import once the host shuts down
Host shutdown only kept guest threads from starting another slice; a thread already inside
guest code kept calling HLE while the services behind it were torn down. Superliminal's job
threads then got a null command buffer from the GPU library, wrote through it, and the process
died with SIGSEGV on its way out.

After shutdown is requested an import now returns to the host entry stub instead of running,
ending that thread's slice; the scheduler already refuses to enter guest code again.

(cherry picked from commit 9e0e8ec0aa8b0bfaa030e5e97d51dbc0223f93e1)
2026-09-30 15:09:29 +02:00
kuba 5ac730ca05 Merge remote-tracking branch 'upstream/main' into integration/all-prs 2026-09-30 14:37:08 +02:00
kuba 556773de50 [VideoOut] Reinterpret the sRGB-encoded frame on a presenter image, not the swapchain
A floating-point display buffer is sRGB-encoded by blitting it into an sRGB image and then
copied byte-for-byte into the UNORM swapchain image. MoltenVK does that copy through a
reinterpreting texture view it caches on the destination; on a presentable image the drawable
behind it changes every frame, and destroying the swapchain then walked those views through a
freed device. Superliminal, whose display buffers are RGBA16F, crashed at every exit (SIGSEGV
in MVKImagePlane::releaseMTLTexture from vkDestroySwapchainKHR) and each crash kept two crash
reporter processes busy for minutes.

The encoded bytes are now copied into a presenter-owned image in the swapchain's format first,
so the swapchain image only ever receives a same-format copy. Frames are unchanged; the exit is
clean.
2026-09-30 14:28:51 +02:00
kuba b5e8527804 [Gpu] Submit on a release-memory label write only when it raises an interrupt
A RELEASE_MEM that writes a 32-bit label submitted the open batch at once. Without an interrupt
nothing inside the slice waits for the label, and every slice that makes progress already ends
with a submit - including one that stops at a WAIT_REG_MEM on that label - so the label is
written when that batch completes either way.

The per-label submits split Superliminal's frames into ~35 extra command buffers; each ended the
render pass, which stores and reloads every attachment on a tile-based GPU. The title menu went
from 15.6 to 21 fps and Octopath from 13-21 to 18-29 fps, with no hang over 150 s runs.
2026-09-30 14:00:56 +02:00
kuba ca76f7c8c8 [Gpu] Age cached images by frame, not by guest submission
The image collector runs after every completed guest submission as well as at each flip, and
every run advanced the age it compares against. A title submits dozens of command buffers per
frame, so "unused for 16 ticks" meant a fraction of a frame: every texture sampled once a frame
was deleted and recreated, and Superliminal uploaded 3,591 textures (2.2 GB) every 5 seconds.
Deleting a GPU-written image the cache cannot read back also dropped its contents.

Only a flip now advances the age. Collection after a submission still runs, so memory pressure is
relieved during long stretches without a flip. Superliminal's per-frame uploads went from ~55 to
none, and its intro scene from 12 to 45 fps.
2026-09-30 13:59:51 +02:00
kuba 0675cfa892 [SpirvTranslator] Structure loops, early exits and single-block programs
Only forward, nested branches were emitted as structured control flow; every program with a
loop, and every single-block program, went through the loop around a switch on the guest PC,
which keeps all registers live and stops the host compiler from optimizing across blocks.

A block that a later block branches back to - on a wave-uniform condition or with s_branch -
now opens a SPIR-V loop whose body is structured like any range, whose continue evaluates
that branch's condition, and whose iterations share the dispatcher's step guard so a guest
loop that never ends still cannot wedge the GPU queue. A conditional branch from the body to
the block after the latch is a break out of the innermost loop. Any other backward edge, or a
break past an outer loop, keeps the dispatcher as before.

Across eight games, programs left on the dispatcher went from 760 to 104 (Poppy, Silent Hill,
Oregon Trail and Dreaming Sarah to none); every emitted module passes spirv-val and the
frames match. Octopath's 12.5M-invocation instanced draw went from 12.2 to 10.8 ms.
2026-09-30 12:59:35 +02:00
kuba e4f0625c81 [SpirvTranslator] Mask a wave32 saveexec result at 64 bits
The low-half mask for s_*_saveexec_b64 on a 32-lane wave used the 32-bit AND helper on the
64-bit exec value, emitting OpBitwiseAnd %uint with a %ulong operand. spirv-val rejects the
module and the driver's behaviour for it is undefined; Octopath has four such programs.
2026-09-30 12:59:31 +02:00
kuba 94933b74d5 [ShaderCompiler] Solve user-data liveness on bit sets and hash graph nodes by id
The liveness fixpoint that picks a program's user-data registers walked 256 booleans per
block per pass; it now works on four 64-bit words per block with the same equations.

ScalarValue keys many graph dictionaries. It keeps reference equality but hashes its unique
id, which skips the runtime's identity-hash path.
2026-09-30 10:34:11 +02:00
kuba df5086f1eb [Cpu] Deliver guest access faults on macOS as signals, not runtime Mach exceptions
The runtime receives EXC_BAD_ACCESS for its threads through a Mach exception port before
the kernel raises SIGSEGV or SIGBUS. It treats a fault in the page holding RSP, or the page
below, as a stack overflow and aborts - assuming RSP is on a stack it owns. Guest code runs on
guest stacks whose pages fault whenever GPU or image write tracking protects them, so Demon's
Souls died with a bare "Stack overflow." about every other minute of play.

Threads now clear that port the first time they enter guest code. Their access faults reach
the signal handler, which resolves guest faults and chains the rest to the runtime's own
signal handlers, as on Linux. Each tracking fault also skips the Mach round trip, which
roughly doubled Demon's Souls' frame rate (about 2 to 4-5 fps).
2026-09-30 10:06:24 +02:00
kuba 4b210515bf [ShaderCompiler] Find each instruction's block by search and reuse register files
Several passes found a block's instructions by scanning the whole program once per block,
and the value graph did it again on every block visit. Blocks are sorted and contiguous, so
IrControlFlowGraph.BlockOf finds an instruction's block by binary search and each pass
groups the program once.

The value graph also allocated two 256-entry register files per block visit. Large Demon's
Souls compute shaders visit thousands of blocks, and the collections that caused stopped the
renderer for about 2.6 s of its first-frame shader work. Replaced entry and exit states are
now reused; a reused state is reset exactly as the constructor would, at the same point, so
the undefined values it starts with and the instructions they are charged to are unchanged.
The resource graphs and SPIR-V of the game's first 134 programs are identical.
2026-09-30 10:06:24 +02:00
kuba a01cffeb7b [HLE] Resolve single-view backing reads and writes without the views lock
Every HLE access to aliased guest memory took one lock shared by all guest threads, and
Demon's Souls' job threads queued on it for 8-byte mutex reads. Readers now binary-search a
copy of the view list; mutations drop the copy under the lock and the next reader rebuilds
it. A reader that races a mutation uses the list from before it, as if it ran first.
2026-09-30 10:06:24 +02:00
kuba 3fe148a262 [Kernel] Place mappings in untouched address space without waiting for the GPU worker
Every mapping change queued behind the GPU worker so it could not race a pending GPU read.
During loading that worker is busy translating shaders, and Demon's Souls' reservations and
batch maps waited seconds for a queue slot (23.6 s over 132 calls, up to 7.1 s each) while
the change itself took about a millisecond.

A change that only places memory where the GPU was never given anything - a kernel-chosen
address, or a fixed range that is empty or reserved and overlaps no registered span - cannot
race a GPU read and has nothing to unregister, so it now runs on the calling thread. Those
paths also skip the unregister request for free and reserved ranges, which are never
registered; waiting on the worker while holding the mapping lock that GPU reads take would
deadlock, so reaching a registered span there throws instead.
2026-09-30 10:06:24 +02:00
kuba 997b7df06f [Kernel] Take APR file sizes from the mount check's stat instead of listing directories
Resolving an APR path already stats every component to rule out links out of the mount.
The same stat now records the file's size, so size lookup no longer lists the file's whole
directory. Listing stats every entry: Demon's Souls keeps up to 7,390 files per asset
directory on a slow disk, and each first lookup in one paid for all of them.

FileInfo reports a missing component as -1 instead of throwing; it still ends the check.
2026-09-30 10:06:08 +02:00
kuba 467877d046 Merge pr/fiber-stack-bounds-windows-only 2026-09-30 02:45:10 +02:00
kuba 6f1075771f [Cpu] Keep fiber switches from writing stack bounds into the macOS TSD
The guest context-transfer stub that fiber switches go through keeps the
Windows TEB stack bounds in sync by storing the target stack top and
bottom to gs:[8] and gs:[16]. Unlike the guest-entry and exception stubs,
it did so on every host. On macOS gs addresses the pthread TSD, where
those slots hold errno's address and another key: a fiber switch wrote
its stack bounds over them, and the next failed libc call on the thread
(a timed-out condition wait) crashed reading errno through the pointer.
Demon's Souls died this way within 10-50 s of boot; a hardware
watchpoint on the thread's errno slot stopped in this stub.

The fiber bounds sync now lives next to the other TEB-bound helpers and,
like them, emits nothing off Windows.
2026-09-30 02:45:09 +02:00
kuba a6d7cfed0c Merge pr/sha-rewrite-register-spans 2026-09-30 00:57:24 +02:00
kuba 64a31401de Merge pr/batch-map-single-transaction 2026-09-30 00:57:24 +02:00
kuba 642f25d88c Merge pr/guest-path-resolution 2026-09-30 00:57:24 +02:00
kuba eb7521543c [Loader] Rewrite SHA instructions in spans that touch no guest memory
The red-zone patcher computes a shifted core for every span: the run of
faultable guest memory accesses that executes with RSP moved below the
red zone. A span over register-only instructions has no such access, so
the core could not be computed and the span was refused as too short.
SHA rewrite sites are exactly that shape (sha256msg1/msg2/rnds2 on
registers), so no SHA instruction was rewritten any more: on hosts
without the SHA extensions every one trapped and was emulated one at a
time. Poppy Playtime logged sha_rewrites=0 with 144 too-short refusals,
hit hundreds of thousands of illegal-instruction traps and stopped making
progress within a minute.

A span with no guest memory access has nothing that must run outside the
shift, and the span builder has already refused any instruction that
touches RSP, so the whole span is the core.
2026-09-30 00:57:23 +02:00
Berk d0dd3fe102
Gran Turismo 7 Fixes, AvPlayer, Razor CPU stubs, Net stubs (#927)
* [AvPlayer] improved video playback sync and stats

* [AvPlayer] enabled threaded video decoding

* [Fiber] fixed current fiber address query

* [Font] added bitmap glyph rendering

* [GPU] added unsigned scaled texture sampling

* [Network] added socket receive and resolver support

* [NpManager] added offline signup status

* [NpSessionSignaling] added signed-out request stubs

* [SigninDialog] added dialog stubs

* [TextToSpeech] added initialization stubs

* [SystemService] added music player disable stub

* [VideoOut] added VRR stubs

* [RazorCpu] added marker stubs

* [Fiber] updated current fiber address test

* [Pad] Added scePadGetFeatureReport stub

* [Pad] For now, extra controller definitions should remain as stubs

* [Runtime] Module loader correct order: libc > libSceNpCppWebApi > libScePfs > logiWheel

* [SystemService] Added sceSystemServiceReenableMusicPlayer stub

* [VideoOut] Add sceVideoOutVrrUnpegFromFixedRate stub

* [Cpu] Reuse exited guest thread stack and TLS regions

* [Kernel] Isolate temp0 storage per game process
2026-09-30 01:37:56 +03:00
kuba aad66f89d5 [Kernel] Run one mapping transaction per sceKernelBatchMap
A mapping change has to be handed off to the GPU worker before any lock the
image and buffer reads need, and the handoff waits for the GPU to drain.
sceKernelBatchMap walked its entries calling the same per-mapping entry points
the single-mapping exports use, so every entry in the batch took its own
handoff and its own drain.

The batch now opens one transaction and runs all of its entries inside it. A
thread-local flag marks that a transaction is already open so a nested entry
point runs directly instead of handing off again, and the flag is cleared in a
finally so an entry that throws cannot leave it set.
2026-09-30 00:30:37 +02:00
kuba 84038be230 Merge #946 (pr/audio-abi-sizes)
# Conflicts:
#	src/SharpEmu.Libs/Audio/AudioOut2Exports.cs
2026-09-30 00:12:39 +02:00
kuba 60d0f0a4b2 Merge #950 (pr/draw-coverage) 2026-09-30 00:12:28 +02:00
kuba f3aa17d482 Merge #949 (pr/quiet-benign-logs) 2026-09-30 00:12:27 +02:00
kuba c1536c8798 Merge #948 (pr/hle-exports) 2026-09-30 00:12:27 +02:00
kuba 5e352878b0 Merge #947 (pr/structured-control-flow) 2026-09-30 00:12:26 +02:00
kuba 34ab5165a6 Merge #945 (pr/agc-interpolant-batching) 2026-09-30 00:12:25 +02:00
kuba 446ea699ed Merge #944 (pr/gpu-memory-allocations) 2026-09-30 00:12:25 +02:00
kuba c518335246 Merge #943 (pr/async-compute-pipelines) 2026-09-30 00:12:24 +02:00
kuba 1f56f7dd57 Merge #942 (pr/guest-thread-stacks) 2026-09-30 00:12:23 +02:00
kuba e702daeb59 Merge #941 (pr/gpu-fewer-drains) 2026-09-30 00:12:23 +02:00
kuba f254d5370a Merge #940 (pr/shader-isa-fixes) 2026-09-30 00:12:22 +02:00
kuba 73bfad7ed2 Merge #939 (pr/import-patch-serialization) 2026-09-30 00:12:22 +02:00
kuba f37b033b68 Merge #938 (pr/videoout-present-races) 2026-09-30 00:12:21 +02:00
kuba d12e404f9a Merge #937 (pr/cpu-fault-handling) 2026-09-30 00:12:21 +02:00
kuba 048933bfb8 Merge #936 (pr/tbdr-render-scope) 2026-09-30 00:12:20 +02:00
kuba 2f3ee0935c Merge #935 (pr/pixel-system-inputs) 2026-09-30 00:12:20 +02:00
kuba 585bf674c6 Merge #934 (pr/native-guest-fast-paths) 2026-09-30 00:12:19 +02:00
kuba ea6ac5028f Merge #933 (pr/spirv-constant-folding) 2026-09-30 00:12:19 +02:00
kuba 77aefa2bf3 Merge #932 (pr/sigterm-shutdown) 2026-09-30 00:12:18 +02:00
kuba 5f269ac87a Merge #931 (pr/sdl-audio-drain-sleep) 2026-09-30 00:12:18 +02:00
kuba d04084b6d5 Merge #930 (pr/wave-lane-state) 2026-09-30 00:12:17 +02:00
kuba 121e6fa062 Merge #929 (pr/audioout2-grain-pacing) 2026-09-30 00:12:17 +02:00