Commit Graph
5577 Commits
Author SHA1 Message Date
SamG-Coder d9d34a47ac fix(libc): translate guest scanning and wide formatting arguments 2026-10-01 12:00:41 +03:00
SamG-Coder 3a651055bb feat(libc): support C locale wide stream input 2026-10-01 11:59:11 +03:00
SamG-Coder 7f834fc415 feat(libc): add C locale conversion and sample runtime exports 2026-10-01 11:58:51 +03:00
SamG-Coder ad6b37ed42 fix(relinker): resolve guest dependencies and lifecycle arrays 2026-10-01 11:57:13 +03:00
SamG-Coder 3c5fe188b7 fix(relinker): forward Windows arguments to guest startup 2026-10-01 11:57:13 +03:00
Yossi Yadgar 058ba1e08d fix(relinker): name the SELF container and the bytes read when the input is not an ELF 2026-10-01 11:47:55 +03:00
boykopovar e57ee5120d Merge pull request #206 from Praetorian0420/main
Implement network control and socket functionality improvements
2026-10-01 11:41:41 +03:00
ljkxandClaude Opus 5.5 f994b4f89f feat(relinker): lower MONITORX and MWAITX for --to-intel
Replace MONITORX with a NOP and MWAITX with PAUSE in place, padded with
NOPs to the original length, instead of failing the relink. MWAITX may
return before its timer or a store to the monitored line, and without an
armed monitor it does not wait, so callers already re-check their
condition; the replacement takes that path every time.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 10:35:23 +02:00
boykopovar 63071deb03 Merge pull request #205 from oneandonlydean/fix/recompiler-fma-mix-op-sel
fix(recompiler): select v_fma_mix source precision by OP_SEL_HI and the half by OP_SEL
2026-10-01 11:32:45 +03:00
boykopovar db5ce0f83c Merge pull request #204 from oneandonlydean/fix/agc-misaligned-buffers-in-shader-data
fix(agc): patch the memory offsets of misaligned guest buffers in the shader data buffer
2026-10-01 11:31:57 +03:00
boykopovar 33e11c7ea2 Merge pull request #203 from oneandonlydean/fix/libkernel-direct-memory-memfd
fix(libkernel): back direct memory with a memfd on Linux
2026-10-01 11:31:43 +03:00
boykopovar 4a73353eda Merge pull request #202 from oneandonlydean/fix/agc-misaligned-draw-snapshots
fix(agc): snapshot misaligned draw inputs from the offset the shader reads
2026-10-01 11:31:30 +03:00
boykopovar 261272909c Merge pull request #200 from ljkx/feat/sha256-to-intel
feat(relinker): lower SHA-256 instructions for --to-intel
2026-10-01 11:31:02 +03:00
boykopovar 4c1a92fe32 Merge pull request #199 from MichonGoddijn231849/fix/command-buffer-reserve
fix(agc): grow a command buffer whose free space is below its reserved words
2026-10-01 11:30:39 +03:00
boykopovar 5ab2fb00ee Merge pull request #132 from oneandonlydean/feat/agc-cb-eliminate-passes
feat(agc): run CB fast-clear eliminate and DCC decompress passes within the DCC model
2026-10-01 11:29:22 +03:00
boykopovar 9623054a12 Merge pull request #181 from oneandonlydean/fix/agc-sample-2d-over-array
fix(agc): sample a 2D instruction over a 2D array texture through its first layer
2026-10-01 11:28:42 +03:00
boykopovar e4eaba6b2e Merge pull request #198 from MichonGoddijn231849/fix/reserve-virtual-fixed
fix(libkernel): honour MAP_FIXED in sceKernelReserveVirtualRange and sceKernelMemoryPoolReserve
2026-10-01 11:28:18 +03:00
boykopovar cfb1f590bd Merge pull request #197 from MichonGoddijn231849/fix/alias-view-granularity
fix(libc): map a shared-memory alias from the allocation granularity below its offset
2026-10-01 11:27:28 +03:00
boykopovar a7fdb497fe Merge pull request #195 from MichonGoddijn231849/fix/guest-module-tls
fix(relinker): give Windows guest modules with TLS an import directory
2026-10-01 11:15:39 +03:00
Dean Galvin aa9a5c02a7 feat(agc): run CB fast-clear eliminate and DCC decompress passes within the DCC model
Draws with CB_COLOR_CONTROL MODE ELIMINATE_FAST_CLEAR (2) or DCC_DECOMPRESS
(6) were rejected as "only normal color rendering with copy ROP". On
hardware these full-target blits write the fast-clear value into the
fast-cleared pixels (or store the pixels uncompressed); the shader's output
never lands. In this driver's DCC model (surfaces stored uncompressed,
uniform fast-clear keys make every read return the clear value) that is:

- keys that are a clear code: the target's texels become that value and
  its keys read uncompressed. Reads see the same values before and after.
- uncompressed keys, or a target without DCC: nothing changes.
- mixed keys (per-block metadata), a mipmapped DCC target (its keys are not
  decoded) or a register clear of a texel over 64 bits: throw.

The texels go into the target's resident image (its refresh already
cleared it to a code's value; the register code is cleared on the GPU with
FillClear) and reach memory through its write-back, or into guest memory
on the CPU when there is no resident image. A resident image made under
other DCC keys is remade under the target's keys by the storage cache
before the pass reads it. DecodeColorMetadataPass
requires the draw to be only that pass: copy ROP, no depth or stencil
work, no multisampling, a viewport and scissor covering each target.
Indirect passes throw. The CB_COLOR decode moves into DecodeColorBuffer,
which also reads CB_COLOR_CLEAR_WORD0/1.

The register clear code (DCC key 0x20) had no value before: its keys were
read as the stored texels. A target under register keys now reads as its
CB_COLOR_CLEAR_WORD texel: a resident target is cleared to it before a draw
renders into it (then its keys read uncompressed), and a non-resident
target's copy starts from it.

Every decision that materializes a clear reads the keys through
CurrentDccKeys, which first waits for the batches up to the newest recorded
writer of the key range. The title's fast-clear fill of the metadata can
still be pending on the GPU when the next draw is decoded; reading the
stale bytes there made a later draw clear the target over the results of
the earlier ones.

The remaining CB modes (resolve, decompress, FMASK decompress) keep the
rejection, which now names the mode.
2026-10-01 20:59:03 +13:00
Dean Galvin 74abc7acc3 fix(agc): sample a 2D instruction over a 2D array texture through its first layer
A shader sampling with MIMG DIM 2D over a T# of type 2D array was
refused: "guest texture dimension disagrees with the shader's declared
image shape (shape 1, dimension 2)". The access carries no slice
coordinate, so the hardware samples slice 0 of the resource view, the
BASE_ARRAY layer, as it does for the storage access of the previous
commit.

A 2D array Texture now also makes a 2D view of that layer
(Texture::FirstLayerView), whether it holds its own snapshot or views the
surface's storage image, and the sampled binding uses it for such an
access. Every other shape/dimension mismatch still throws.
2026-10-01 20:57:49 +13:00
boykopovar aa74ed81b9 Merge pull request #193 from arreina/pr/elf-reader-overflow
fix(relinker): keep ELF bounds checks from overflowing
2026-10-01 10:53:23 +03:00
boykopovar 89570be51b Merge pull request #191 from asimplestray/feat/shader-vopc-cmpx
feat(shader): implement VOPC I16/U16 cmpx compares
2026-10-01 10:52:25 +03:00
boykopovar e0b923621b Merge pull request #178 from oneandonlydean/fix/agc-label-waits-after-submission
fix(agc): satisfy label waits from stores made after their submission
2026-10-01 10:50:47 +03:00
boykopovar aca6566746 Merge pull request #166 from asimplestray/feat/libc-tail
feat(libc): implement RaiseEv, catchReturnFromMain and reallocalign
2026-10-01 10:50:27 +03:00
boykopovar 116351b242 Merge pull request #163 from MichonGoddijn231849/fix/dcc-key-fill-coverage
fix(agc): make DCC key fills clear what reads through the surface's keys
2026-10-01 10:50:04 +03:00
boykopovar 8764959f2c Merge pull request #137 from oneandonlydean/fix/pixel-inputs-at-parameter-slots
fix(recompiler): declare pixel shader inputs at their parameter slots
2026-10-01 10:49:16 +03:00
boykopovar bc3528be44 Merge pull request #136 from oneandonlydean/feat/pixel-input-vgpr-layout
feat(agc): centroid pixel inputs and NoPerspective by I/J pair
2026-10-01 10:49:01 +03:00
boykopovar 4a78540e38 Merge pull request #134 from oneandonlydean/feat/recompiler-structurize-by-cloning
feat(recompiler): structurize externally entered selection regions by cloning or route variables
2026-10-01 10:48:35 +03:00
Dean Galvin edb1358117 fix(agc): bind a 2D storage access to a 2D array surface as its first layer
A compute shader addressing an image with MIMG DIM 2D over a T# of type 2D
array was refused ("guest storage texture dimension disagrees with the
shader's declared image shape"). Such an access carries no slice
coordinate, so the hardware reads and writes slice 0 of the resource view,
which is the BASE_ARRAY layer of the surface.

The storage element is now bound through a 2D view of that layer of the
surface's shared storage image (StorageTexture::FirstLayerView, created on
demand per mip and released with the image). Every other shape/dimension
mismatch still throws, and both mismatch messages now name the shape and
the dimension.

The recorder test device sets formatProperties, which storage images need
to pick their Vulkan format.
2026-10-01 10:23:36 +03:00
boykopovar 74f84dd048 Merge pull request #130 from oneandonlydean/feat/agc-texture-min-lod
feat(agc): apply a texture descriptor's MIN_LOD clamp through the image view
2026-10-01 10:17:19 +03:00
Praetorian0420 e3eeac4a81 Implement network control and socket functionality improvements
- Enhanced the network control library to check for host addresses and update connection states accordingly.
- Added support for socket operations including connect, listen, accept, send, and recv in the UDP and TCP socket implementations.
- Introduced error handling for various socket operations, ensuring proper feedback for unsupported actions.
- Created comprehensive tests for both TCP and UDP socket functionalities, validating the expected behavior of the network stack.
- Refactored existing code to improve clarity and maintainability, including the removal of unused functions and the addition of necessary error checks.
2026-09-30 23:29:01 -05:00
Dean Galvin b556b87db3 fix(recompiler): select v_fma_mix source precision by OP_SEL_HI and the half by OP_SEL
v_fma_mix_f32 and v_fma_mixlo/hi_f16 read a source as f16 when its OP_SEL_HI bit is set, with
OP_SEL choosing the high half; otherwise the source is an f32. readMixF32 had the two bits swapped,
so a low-half f16 source (op_sel_hi set, op_sel clear) was read as the whole register's f32 bits.
PPSA21564's material shaders lerp packed f16 colours this way: red and blue (the low halves)
collapsed to near zero while green and alpha survived, giving the green cast on lit surfaces.

agc_driver_mix_precision_tests runs the mix encodings on the GPU against a model of the guest
instructions.
2026-10-01 16:21:48 +13:00
Dean Galvin 81d6f94ceb fix(agc): patch the memory offsets of misaligned guest buffers in the shader data buffer
A guest buffer view off minStorageBufferOffsetAlignment is bound from the
aligned offset below it, and the difference goes into the shader's memory
byte offsets (3dec6ced), but only when those live in the push constants:
a shader whose shader data is a buffer failed with "a guest buffer off the
storage buffer offset alignment in a shader whose shader data is a buffer
is not implemented".

The adjustment now goes into the shader data buffer's byte at
memoryOffsetDword * 4 + element, and a template's data refresh writes the
dispatch's words with the same patches applied.
2026-10-01 16:09:16 +13:00
Dean Galvin d544596283 fix(libkernel): back direct memory with a memfd on Linux
std::tmpfile() places the shared direct memory backing in /tmp, so a
title's direct memory counts against that filesystem's size (a tmpfs is
half of RAM by default): once /tmp fills, touching a backing page raises
SIGBUS. memfd_create gives the same shared memory pages without a
filesystem or its size limit.
2026-10-01 16:06:42 +13:00
Dean Galvin f5355d917a fix(agc): snapshot misaligned draw inputs from the offset the shader reads
A guest buffer view off minStorageBufferOffsetAlignment is bound from the
aligned offset below it, and the shader adds the difference to every
access (3dec6ced). PrepareDrawBindings (9f1c680b) copied such a read-only
in-place view into a snapshot that starts at the view itself, so the
shader read the snapshot that many bytes past the view.

The snapshot now covers the view from the binding's start.
2026-10-01 16:05:24 +13:00
asimplestray 889af1d542 feat(shader): implement VOPC I16/U16 cmpx compares 2026-09-30 23:55:29 +00:00
asimplestray 4816e105ad fix(tests): match default convention of ApplicationHeapRealign 2026-09-30 23:55:00 +00:00
asimplestray b42db4b6f3 feat(libc): implement RaiseEv, catchReturnFromMain and reallocalign 2026-09-30 23:55:00 +00:00
ljkxandClaude Opus 5.5 e66b0b34d7 feat(relinker): lower SHA-256 instructions for --to-intel
Lower SHA256RNDS2, SHA256MSG1 and SHA256MSG2 (register forms) out of line
with legacy SSE2 instructions only, so relinked code no longer needs
SHA-NI. Consecutive short SHA-256 and SSE4a sites share one stub. The
SSE4a stub builder moves to StubBodyBuilder for reuse; IsShaNi now also
recognises SHA256RNDS2 (0F 38 CB). Memory operand forms fail the relink.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-01 00:20:43 +02:00
MichonandClaude Opus 5.5 548162a203 fix(agc): grow a command buffer whose free space is below its reserved words
A command buffer with fewer free dwords than reserved_dw (an empty one whose
title allocates its storage in the callback, as Marvel's Wolverine does)
threw "reserved space exceeds command buffer capacity" before its callback ran.
Its available space is now 0, so the allocation goes to the callback with the
reserved words added, as for any other full buffer.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 00:02:31 +02:00
MichonandClaude Opus 5.5 1d806a4688 fix(libkernel): honour MAP_FIXED in sceKernelReserveVirtualRange and sceKernelMemoryPoolReserve
Both ignored the flags and the requested address and reserved wherever the arena
had room, so a title that reserves a fixed range (Marvel's Wolverine passes
0x400010, MAP_FIXED | MAP_NO_COALESCE) and then uses the address it asked for
touched memory it never reserved. A fixed reservation now lands at the address,
after checking the range is free; other reservations are placed as before.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-01 00:00:22 +02:00
MichonandClaude Opus 5.5 e404e7f0aa fix(libc): map a shared-memory alias from the allocation granularity below its offset
MapViewOfFile3 takes an offset that is a multiple of the allocation granularity
(64 KiB), while shared guest pages are 16 KiB. An alias of a range starting at
a 16 KiB page that is not 64 KiB aligned was refused ("the section offset is not
a multiple of the allocation granularity"), so its host import failed. The view
now starts at the granularity boundary below the offset, the alias points past
the lead, and unmapping rounds back to the view's base.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-30 23:57:56 +02:00
MichonandClaude Opus 5.5 d29a1296cd fix(relinker): give Windows guest modules with TLS an import directory
The Windows loader sets up TLS for a dynamically loaded DLL only when it snaps
the DLL's imports. Guest modules had no import directory, so their TLS
directory was never processed: every guest module kept TLS index 0 and read
and wrote the executable's TLS block. A guest libc's thread-locals (gmtime's
buffer at +0x39c in Marvel's Wolverine) then ran past the executable's
0x150-byte block into the process heap, and corrupted a loader node that
crashed the next thread start in ntdll. Guest modules with TLS now import from
KERNEL32, as the executable does.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-30 22:47:50 +02:00
Dean Galvin 258e4d526d fix(agc): fuse geometry shader halves into one self-contained program
sceAgcUnknownFuseShaderHalves (fd4700b9) fuses both kinds of halves at
the register level: the back half's registers with the front half's
program address in PGM_LO_ES (PGM_LO_LS for hull halves). For geometry
halves the driver then compiles that front half as the draw's whole
program (type 4, Stage::Mesh) and skips the back (Role::GeometryBack);
nothing links the two. The front ends in s_setpc_b64 s[6:7] and has no
s_endpgm, so the decode runs on into the s_code_end padding and the
program trailer. In PPSA21564 the geometry shader draws were skipped
with "unsupported SOPP opcode 31" (s_code_end) and "unsupported scalar
source operand code 115 at program counter 64".

Geometry halves are now fused into one Gs program: the front half's code
up to its final s_setpc_b64 s[6:7] (its length comes from the program
trailer), s_nop padding to the next 256 bytes, then the whole back half,
so the front falls through into the back. Its SH registers are the back
half's, with PGM_LO/HI_GS pointing at the copied back code, the ES
program address at the fused code, RSRC1 taking the larger VGPR and SGPR
counts of the two halves, RSRC2 taking the front half's user-SGPR count
(the SPI loads the front layout; the back reloads its own from memory
through s[0:1]), and the front's other SH registers except its checksum
appended. Context registers are merged the same way. Inputs come from
the front, outputs, specials and user data from the back; the scratch
size is the larger of the two.

Everything the fused Shader points to, including a copy of the header
itself, is written into the caller's memory after the code, and the
header is registered with the driver as a self-contained shader. Titles
pass memory without honouring the reported alignment, so the program is
placed at the first 256-byte boundary inside it, and the size query
returns the total plus 255 bytes of padding (alignment reported as log2
8). Halves with embedded constant buffers, a front half without a
trailer or final s_setpc_b64, a front half that needs RSRC2 state the
back half does not enable, and geometry halves without fused memory
throw.

Hull halves keep the register-level fusion, which the tessellation
path's separate local and hull programs fit. The half-type and stage
checks stay shared.

The driver now loads s[0:1] of a Gs program from its user-data address
registers whenever they are set, not only for GsFront programs, since
the back half of a fused program reloads its user data from there; a
program without those registers keeps zero there (from SamG-Coder's
8345fbc1).
2026-10-01 08:45:51 +13:00
MichonandClaude Opus 5.5 4ce40333ea fix(agc): make DCC key fills clear what reads through the surface's keys
A buffer fill that starts at a surface's DCC keys and covers at least its key range (titles fill
the padding too) is a key fill. A uniform key fill leaves the image's texels and pending results
in place and records the fill's code: a sampled read through the surface's keys binds the clear
value, a color target through the keys starts from it at its next refresh, and reads that bypass
the keys still see the texels. Key scans return the fill's code until its write lands, and a
write-back of results drawn before the fill keeps the keys holding that code. The immediate clear
of the covered images is opt-in (APS5_KEYS_FILL_CLEAR=1): it fixes titles whose sampled reads
reach the pending image before a refresh, at the cost of reads that bypass the keys (Astro Bot's
title logo, reported by @oneandonlydean).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-30 21:40:15 +02:00
Dean Galvin a36ef52b33 fix(agc): decide a 64-bit label wait by the dwords its mask compares
A WAIT_REG_MEM_64 whose mask leaves the high dword out compares the low
dword alone, but the wait paths looked for all eight bytes: the
recorder's label table and the stores committed since the submission
want an entry for each dword, while a producer's RELEASE_MEM or
WRITE_DATA stores 32 bits, so neither ever satisfied such a wait, and the
held-at-submission check refused it when an earlier packet stored the
unrelated high dword.

Pm4::WaitAwaitedBytes gives the bytes that decide the compare (4 for
WAIT_REG_MEM and for a WAIT_REG_MEM_64 whose high mask dword is zero,
else 8), and the wait paths use it. The timeout report now prints a
64-bit wait's reference and mask (it printed the reference's two halves
as "ref" and "mask").
2026-10-01 08:39:53 +13:00
Dean Galvin 7df4ce4007 fix(agc): satisfy label waits from stores made after their submission
A title may reclaim a label (reset it to 0) as soon as the submission
that released it is done, trusting every queue waiting on it to have
passed its WAIT_REG_MEM within microseconds, as the CP polls from the
moment it reaches the wait. A worker that reaches a later wait of the
same submission long after (it records and compiles in between) found
the reset label and timed out.

A memory wait now also passes when
- a label store the driver committed (recorded on the GPU, as a
  completion action, or on the CPU) after the wait's submission gave the
  awaited bytes a value the wait accepts (the last four stores per dword,
  with their eventSerial stamps). Such a store belongs to this use of the
  label or a later one, since the title reset it before submitting.
- the awaited bytes held such a value when the game submitted, and no
  earlier packet of the queue (in the submission, or one still queued or
  running) stores to them.

A store made before the submission never satisfies a wait.
2026-10-01 08:39:53 +13:00
Dean Galvin 6a33a3d371 fix(recompiler): declare pixel shader inputs at their parameter slots
SPI_PS_INPUT_CNTL_n.OFFSET (bits 0-5) names the parameter slot pixel
input n reads, so several inputs may read one slot and an input may read
a slot the vertex stage never exports. With OFFSET bit 5 set and
FLAT_SHADE clear the input is the DEFAULT_VAL constant instead (bits 8-9:
0000, 0001, 1110, 1111). With OFFSET bit 5 and FLAT_SHADE both set the
slot in the low bits is passed through with its three vertices unchanged:
v_interp_mov P0, P10 and P20 read vertices 0, 1 and 2 rather than P0,
P1-P0 and P2-P0. The PS5 compiler writes such inputs as 0x422 and 0x423.

The old mapping masked OFFSET to five bits, so a defaulted input landed
on a real slot, and gave the second of two inputs reading one slot either
the same Location (two variables, "duplicate shader interface location")
or, when one was flat, a free Location the vertex stage never wrote
("graphics interfaces disagree at location N").

Now one input variable is declared per slot actually read, at Location =
slot, and inputs reading that slot share it. A slot read both flat and
interpolated (or through the perspective and linear pairs) is read per
vertex: flat readers take the provoking vertex, the others interpolate
with the barycentrics of their own pair. Pass-through inputs are read per
vertex at their slot without subtracting vertex 0, and reading one with
v_interp_p1/p2 is refused. Defaulted inputs read their DEFAULT_VAL
constant and declare nothing; inputs the program never reads are no
longer declared.
2026-10-01 08:38:47 +13:00
Dean Galvin cb66ec2004 feat(agc): centroid pixel inputs and NoPerspective by I/J pair
SPI_PS_INPUT_ENA/ADDR with PERSP_CENTROID (bit 2) or LINEAR_CENTROID
(bit 6) was rejected; PPSA21564 binds 0x326 (perspective center and
centroid, linear center, POS_X/Y).

The PS input VGPR layout now follows the hardware rule: SPI_PS_INPUT_ADDR
places every input it names in SPI order (two VGPRs per I/J pair, three
for the pull model, one otherwise), loaded or not, and ENA & ADDR selects
the loaded ones. ShaderPixelStageInfo carries inputAddr (replacing
perspectiveCenterVgpr) plus perspectiveCentroid and linearCentroid; the
recompiler places each loaded input with PixelInputVgpr. This also fixes
the system inputs, which were always written from v0 (psSystemInputBase
was never set), so POS_X overwrote the center I in any draw with
barycentrics enabled.

Draws are rasterized single-sampled, where the centroid is the pixel
center: with fragment barycentrics the centroid pairs carry the center
barycentrics (BaryCoordKHR for perspective; the linear center and
centroid pairs now get BaryCoordNoPerspKHR).

NoPerspective was decided for every parameter by one flag (LINEAR_CENTER
loaded). v_interp_p2 now records whether it reads the J of a linear or a
perspective pair, and a parameter is NoPerspective when it is read
through a linear pair; parameters read through neither keep the old
rule. A parameter read through both kinds of pair throws. Only pixel
stages consult this.

The request serializer moves to version 5 (older requests read back with
their loaded inputs as the layout); the cache key and the driver's draw
key compare and hash the new fields. The unsupported-input error names
ENA and ADDR.
2026-10-01 08:37:45 +13:00