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.
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).