sceAgcDebugRaiseException (NID T6xuVw0KUJo) now logs the exception id
with APS5_LOG_OUT and returns 0, as libkernel's
sceKernelDebugRaiseException does.
Palworld PPSA23126 (#2598) and 007 First Light PPSA11386 (#2523) import
it; neither is shown calling it.
OpenAGC 3c7e8072 (src/game_compat.c) returns 0 and says the function is
a no-op on retail hardware; the ud2 trap it describes for development
hardware is not reproduced. KytyPS5 6f0cddd4 (src/libs/agc.cpp) takes a
uint32 exception_id, logs it and returns 0. OpenAGC declares no
arguments, but a body that only traps reads none, so the uint32 is kept
and the conflict is recorded in TechnicalDebt. The aerolib name is from
zecoxao/sce_symbols 2883963a; ps5-payload-dev/sdk f5d40f02 has only an
untyped stub.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
OpenAGC's include/agc_nids.h names three more of the raw-NID exports, and
each name hashes to its NID:
gQkqkLttcpw sceAgcAcb_gQkqkLttcpw -> sceAgcAcbAtomicGds_0900
dolOmWH+huQ sceAgcUnknownGetFusedShaderSize -> sceAgcGetFusedShaderSize_0080
V++UgBtQhn0 sceAgcGetDataPacketPayloadAddressUnk -> sceAgcGetDataPacketPayloadAddress_0090
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eight libSceAgc exports were published under a raw NID with a made-up
name. Each NID is the hash of a versioned SDK name (checked with
tools/nid_names.py compute_nid), so the functions now carry that name and
are exported from it directly:
23LRUSvYu1M sceAgcUnknownInitState -> sceAgcInit_0090
-KRzWekV120 sceAgcUnknown__MKRzWekV120 -> sceAgcDcbSetIndexSize_0600
Ikfdt-rIqCE sceAgcUnknown_Ikfdt_MrIqCE -> sceAgcJumpPatchSetTarget_0300
7Wa3aeJgeVU sceAgcUnknown_7Wa3aeJgeVU -> sceAgcBranchPatchSetThenTarget_0300
rP5xLdOf26k sceAgcUnknown_rP5xLdOf26k -> sceAgcBranchPatchSetElseTarget_0300
fd5Bp5tGTgo sceAgcUnknownFuseShaderHalves -> sceAgcFuseShaderHalves_0200
qj7QZpgr9Uw sceAgcDcbContextStateAnotherOp -> sceAgcDcbContextStateOp_0100
k0E7vkgqAuE sceAgcCreateInterpolantMappingVsPs -> sceAgcUpdateInterpolantMapping_0100
The exported NIDs are unchanged; the extra exports under the hashes of the
made-up names are gone. Behaviour is unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceAgcUnknownGetFusedShaderSize and sceAgcUnknownFuseShaderHalves
require a front half to end with s_setpc_b64 s[6:7] (0xbe802006), the
jump to the back half, before its s_code_end padding. PPSA16064
(Minecraft Dungeons II, Unreal Engine) has front halves that end with
0xbefd2106 instead, and the size query threw "front half does not end
with s_setpc_b64 s[6:7]".
0xbefd2106 is SOP1 S_SWAPPC_B64 (opcode 0x21) with SSRC0 s[6:7] and
SDST 125, the NULL register (RDNA2 ISA, SOP1 and the scalar operand
table): it jumps to s[6:7] and discards the return address, the same
transfer as s_setpc_b64 s[6:7]. Fusion drops this instruction and pads
to the back half with s_nop either way, so both forms are accepted. Any
other last instruction still throws.
agc_shader_fusion runs the full fusion check on a front half ending
with the s_swappc_b64 form; on main it fails with the title's error.
Return the version 0 internal register defaults, the internal
counterpart of sceAgcGetRegisterDefaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
sceAgcGetIsTrinityMode takes a pointer to a one-byte flag; the only
known caller ignores the return value. The export took no argument and
never wrote the flag. That caller's flag is in zero-initialised .bss,
so this corrects the signature; it does not fix a visible failure.
The function now stores false, as sceKernelIsTrinityMode reports a base
PS5, returns 0 and throws on a null pointer, whose error code is
unknown. It moves from Unimplemented.cpp to Misc/src/Platform.cpp, and
the new agc_platform_tests ctest target covers it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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).
Only the lines this branch added lose their comments; the commits before
keep them, with the reasoning behind each change, for whoever digs into
that code later.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- packet sizes for the existing builders and the tessellation ring
config
- direct register writes and end-of-pipe action data, type and cache
patches
- GS/HS shader halves fused by merging their registers, after Kyty
- jump target patches; reserved jumps are allowed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments in this codebase may only mark technical debt (human-added
only), the end of #endif, and the end of a namespace, per
docs/dev/CONVENTIONS.md. Remove the inline rationale comments added in
the AGC PM4 opcode and shader recompiler robustness commits; the code
itself, the commit history, and the PR description now carry that
context instead.
Notably, Command::WriteMemSemaphore takes the corrected 4-argument
form (address, waitForMailbox, signalType, operation): an earlier
revision of this helper used a different, incompatible argument
order. sceAgc*MemSemaphore callers derive waitForMailbox/signalType
from the low two bits of clientCode, and operation from action
(0 = signal, 1 = wait). This ABI note previously lived as an inline
comment; it is recorded here instead per the no-comments convention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fills in guest-facing sceAgc* entry points across Acb/Cb/DcbDraw/DcbFlow/DcbState/Misc
that were still stubbed with NotImplemented_nid_no_patch on current upstream, one layer
below upstream's Recorder rearchitecture:
- Command/Control.{hpp,cpp} (new): WriteJump, WriteRewind, WritePredication,
WriteMemSemaphore helpers shared by the Acb/Dcb entry points below.
- Command/Memory.{hpp,cpp}: WriteCopyData, WriteAtomicMem helpers.
- Acb/Control.cpp: Jump/JumpGetSize, Rewind/RewindGetSize.
- Acb/Dispatch.cpp: DispatchIndirectGetSize.
- Acb/Memory.cpp: AcquireMemGetSize, CopyData(+Size), AtomicMem(+Size),
AtomicGdsGetSize, PrimeUtcl2(+Size).
- Acb/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize, EventWriteGetSize,
QueueEndOfShaderActionGetSize, MemSemaphore.
- Cb/Dispatch.cpp: DispatchGetSize only (sceAgcCbDispatch itself left untouched --
upstream's modifier mask 0xa038u|0x41u there is correct as-is).
- DcbDraw/DrawIndexed.cpp: DrawIndexMultiInstanced(+GetSize), still unimplemented
even after upstream's own indexed-draw work.
- DcbFlow/Control.cpp: Jump, Rewind(+Size), and a real WaitUntilSafeForRendering that
emits AgcDriver::RenderingWaitPacketHeader (recognized by the executor's fence wait
in Driver.cpp) instead of upstream's plain-NOP stub, which the executor does not
special-case.
- DcbFlow/Memory.cpp: AcquireMemGetSize, CopyData(+Size), DmaDataGetSize,
AtomicMem(+Size), AtomicGdsGetSize, WriteDataGetSize.
- DcbFlow/Sync.cpp: CondExec(+Size), WaitOnAddressGetSize,
StallCommandBufferParserGetSize, MemSemaphore.
- DcbState/Predication.cpp: SetPredication only (the file's 3 GetSize functions are
left as upstream's diagnostic stubs, not real fixes).
- Misc/PacketInfo.cpp: sceAgcDcbGetSystemSoftwareVersion.
ABI correction: Command::WriteMemSemaphore takes the corrected 4-argument form
(address, waitForMailbox, signalType, operation). The Acb/DcbFlow sceAgc*MemSemaphore
entry points still expose the older (action, clientCode, address) guest signature;
their bodies now decode `action` into the signal/wait operation and the low two bits
of `clientCode` into signalType/waitForMailbox before calling the corrected helper.
Not ported (already superseded or out of scope per review): WriteMarker/WriteCustomNop/
WriteEventWrite/WriteCondExec/WriteDispatchIndirectAddress (duplicate upstream's
existing Marker/EventWrite/DispatchIndirect logic), Acb DmaData/DmaDataGetSize/
WriteData/EventWrite (already implemented upstream), DcbFlow EventWrite(+Size)
(upstream's version handles the 8-byte occlusion-address case more completely),
DcbDraw's other DrawIndex* entry points (already implemented upstream),
Misc/Trinity.cpp, Patch/WriteData.cpp, DcbState/Marker.cpp (all superseded by
upstream equivalents).