Repository navigation
fix(agc): write the console's DRAW_INDEX_MULTI_INST packet for sceAgcDcbDrawIndexMultiInstanced - #11313
Conversation
…DcbDrawIndexMultiInstanced On a PS5 the builder writes 15 dwords: a tag write of 0xc6000006, opcode 0x3a with its arguments, initiator 0x80 whatever the modifier, and a closing tag write; GetSize returns 60. AnyPS5 wrote NUM_INSTANCES and DRAW_INDEX_2 under argument meanings nothing confirms. The driver refuses 0x3a, whose field meanings are not known, and names it DRAW_INDEX_MULTI_INST as Linux's nvd.h does.
|
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed the packet builder against the attached PS5 capture matrix and the cited gfx10 packet layout. The emitted 15 dwords, tag framing, 0x80 initiator, 60-byte size, and deliberately unchecked/aliased input values match the evidence stated in the PR; the implementation correctly avoids claiming the argument semantics or shader-visible object-ID behavior are understood. The PM4 path now refuses opcode 0x3a with a specific reason instead of executing the prior guessed draw, and debt records the remaining uncertainty. The reported Windows main/control/change tests and same-GPU validation-layer comparison are detailed; hosted eligibility, conventions, intake, labels and report checks pass, while product and relinker jobs were skipped by path policy. No blocking issue found.
|
@frankea One test change: |
MarcZX10
left a comment
There was a problem hiding this comment.
The measured builder implementation and its 12-call word/size regression are supported by the PS5 capture evidence in the PR. I agree with the maintainer's follow-up on the PM4 test: tests/Pm4.cpp currently asserts that a structurally valid DRAW_INDEX_MULTI_INST packet is rejected as unimplemented. That makes the test fail as soon as the driver gains support for the packet, even though the builder behavior remains correct. Please remove that rejection assertion while retaining the opcode-name assertion and the focused builder-word/size regression; the conservative runtime refusal and its debt documentation can remain until execution semantics are established.
|
@oneandonlydean @MarcZX10 Done in 549368f: the AI-assisted: yes (Claude Code) |
What
On a PS5,
sceAgcDcbDrawIndexMultiInstanced(cb, a1, a2, a3, a4, modifier)writes 15 dwords andsceAgcDcbDrawIndexMultiInstancedGetSizereturns 60:The initiator is 0x80 whatever the modifier, and the builder checks no argument: null and odd addresses, zero counts and 0xffffffff are written as given. AnyPS5 wrote 8 dwords (
NUM_INSTANCESwith a4, thenDRAW_INDEX_2reading a1 as the index count and a2 as the index address), threw for a non-null a3 and returned 32. The builder now writes the console's words and GetSize returns 60.Measurement: PS5 on firmware 13.40, inside Gran Turismo 7 (PPSA01317), 2026-10-24 and 2026-10-25. A payload attached to the game with ptrace and called the game's own
libSceAgcbuilder on a 0x200-byte command buffer filled with 0xcc; every call advanced the cursor by 60 bytes and wrote the two tag writes above around the packet. With ia = 0x123456789a00 and oa = 0x222233334440:What the four arguments mean is not known, and so neither is what the packet draws. Opcode 0x3a is
DRAW_INDEX_MULTI_INSTon gfx10 (Linuxnvd.h). AMD's PFP layout of that packet, as carried in Google Dive'spfp_pm4_packets.h, is instance count, object ID address, max size, index base, index count, initiator. Laid over the console's words, that makes a1 the instance count, a2 the object ID address, a3 the index base and a4 the index count, with the max size clamped to at least 1 the way AnyPS5'ssceAgcDcbDrawIndexOffsetclamps it. That is the reverse of the names AnyPS5 and SharpProspero give the arguments (index count, index address, object IDs, instance count). Initiator bit 7 isUNROLLED_INST(gc_10_1_0_sh_mask.h): the command processor unrolls the instances, and how each one gets its object ID and instance ID is not documented.So the driver does not guess: it refuses 0x3a with
DRAW_INDEX_MULTI_INST is not implemented: which fields hold the instance count, object ID address, index base and index count, and how object IDs reach the shaders, are not knowninstead of the generic draw message, and the opcode catalog names 0x3aDRAW_INDEX_MULTI_INST(it saidDISPATCH_DRAW_PREAMBLE, whichnvd.hputs at 0x8c). The argument names in the header stay as they were; the libSceAgc and libSceAgcDriver debt files record both open questions.Behaviour change: a title that calls the builder now stops when it submits the packet, with the refusal above. Before, a call with a null a3 drew the guessed instanced draw, and a non-null a3 threw in the builder. Of the six titles whose imports I checked (Astro Bot, Ghostrunner, Gran Turismo 7, Horizon Call of the Mountain, NHL 26 and Onimusha), only Ghostrunner (PPSA03685) imports the function. In a Ghostrunner run on
main14eb2cd + #9703 with a local trace of the builder's arguments, RTX 4090, the title made no call before it stopped on #7459 at 147 s.Tested
Windows 11 (build 26200), MinGW GCC (WinLibs 15.2) Release build with
BUILD_TESTING=ON, each test run three times (ctest --repeat until-fail:3).mainca6e29e (head 549368f), withagc_driver_pm4's assertion that the driver refuses the 0x3a packet removed: the 41 ctest entries below pass 41/41, and 41/41 under the validation layer (same settings as below), where the loader inserted the layer and the log has noVUID-line orwas not found but was requested by env var VK_INSTANCE_LAYERS.mainca6e29e passes its 40 the same way.agc_draw_index_multi_instanced(new) checks the size and the 15 words of each of the twelve measured calls above against the console's.agc_driver_pm4checks that the catalog names 0x3aDRAW_INDEX_MULTI_INST.libSceAgctest executables plusagc_draw_index_multi_instanced_tests,agc_driver_pm4_testsandagc_driver_pm4_replay_tests:main14eb2cd): 41/41.main14eb2cd with only this PR's tests:agc_draw_index_multi_instancedfails (multi-instanced draw size is not 60 bytes) andagc_driver_pm4fails (opcode 0x3a is not DRAW_INDEX_MULTI_INST); the other 39 pass.main14eb2cd: 40/40 (it has noagc_draw_index_multi_instanced).VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation, Vulkan SDK 1.4.363.0, withVK_LOADER_DEBUG=layer,ANYPS5_NO_SHADER_CACHE=1,ANYPS5_REQUIRE_VULKAN=1andctest -V) on the same entries: this PR 41/41 andmain40/40; the loader inserted the layer, and neither log has aVUID-line orwas not found but was requested by env var VK_INSTANCE_LAYERS.tools/check_conventions.py --base origin/mainpasses.Overlap
#11290 and #11306 (mine) change the indexed indirect multi draw and the tag headers next to this builder; each merges with this branch without conflicts. 151 open PRs change the same files, mostly the two debt files and
libSceAgc'sCMakeLists.txt; none of them conflicts with this branch beyond its own conflicts withmain, and none changes opcode 0x3a or this builder.Checklist
main; no other open PR implements the same functions.NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)