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>
The builder threw on a null indirect base, while the PM4 executor accepts
SET_BASE with address 0 (it only requires the alignment and address bits) and
an indirect draw that later reads the base is checked there. Titles clear the
base with 0, as with sceAgcDcbSetIndexBuffer, which already accepts 0 to
unbind. A non-null base is still checked for 8-byte alignment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#1629 makes sceAgcDcbResetQueue throw 'unsupported op bit 0x40' (and for
0x200/0x400). Dreaming Sarah and Astro Bot call it with op bit 0x40 at
start-up, so both abort before the first frame. Main with only #1629
reverted runs Dreaming Sarah normally again (59.9/59.9 fps, no skipped
draws, no flashes).
sceAgcCreatePrimState only packs registers, but it now also resolves the
graphics ABI ahead of time, and that resolve throws when the primitive
type is a patch list without HS_EN or a hull stage with another type.
No draw can use such a state, so leave it to draw time and return the
registers. Bit 2 of VGT_SHADER_STAGES_EN is HS_EN, not an NGG bit.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Replace the CLEAR_STATE approximation with the envelope and per-op-bit packet groups measured on PS5 firmware 13.60. Emit groups for op bits 0x001, 0x002, 0x004, 0x008, 0x010, 0x020, 0x080, 0x100 and 0x800 in ascending order; throw for 0x040, 0x200 and 0x400 whose packets the driver rejects. state 2 sets the envelope flag and state 3 sets the 0x004 and 0x800 group payload dword.
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.
Every command writer checked bottom <= cursor_up <= cursor_down <= top.
PPSA16064 (Minecraft Dungeons II, Unreal Engine) builds small one-packet
buffers (8 dwords) with cursor_down left null, and the first
sceAgcDcbCopyData into one threw "invalid command buffer cursors".
Nothing in the library allocates downward, so cursor_down only bounds
the space above cursor_up. A null cursor_down now means that bound is
top. Non-null cursors are checked as before. TechnicalDebt records the
assumption.
agc_commands writes six dwords into such a buffer and checks that a
further allocation past top fails without moving the cursor.
Return the version 0 internal register defaults, the internal
counterpart of sceAgcGetRegisterDefaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write the 2-dword CLEAR_STATE (0x12) packet with a 4-bit command, the
packet the driver already validates and executes by restoring the
initial context registers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write SET_CONFIG_REG (0x68) packets like the context, shader and user
config register setters: one register from a ShaderRegister, or a range
of values at an offset.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>