agc: implement branch target patching and packet size queries

This commit is contained in:
nmzik
2026-10-09 03:33:47 +02:00
parent a31e2cd361
commit 3ae5a9b70a
4 changed files with 102 additions and 13 deletions
+50
View File
@@ -41818,6 +41818,56 @@ void CheckPm4IndirectControlFlow(RenderContext &renderer) {
}
}
std::array<uint32_t, 5> cx_packet{};
CommandBufferLayout cx_dcb{cx_packet.data(), cx_packet.data() + cx_packet.size(),
cx_packet.data(), cx_packet.data() + cx_packet.size(),
nullptr, nullptr, 0};
const ShaderRegister cx_register{Pm4::CB_TARGET_MASK, 0x76543210u};
Require(name, "indirect context packet size",
Gen5::AgcDcbSetCxRegistersIndirectGetSize() == sizeof(cx_packet) &&
Gen5::AgcDcbSetCxRegistersIndirect(
reinterpret_cast<Gen5::CommandBuffer *>(&cx_dcb), &cx_register, 1) ==
cx_packet.data() && cx_dcb.cursor_up == cx_dcb.top,
"indirect Cx size did not match the emitted command buffer");
std::array<uint32_t, 14> patched_branch{};
CommandBufferLayout branch_dcb{
patched_branch.data(), patched_branch.data() + patched_branch.size(),
patched_branch.data(), patched_branch.data() + patched_branch.size(),
nullptr, nullptr, 0};
Require(name, "branch packet size",
Gen5::AgcCbBranchGetSize() == sizeof(patched_branch) &&
Gen5::AgcCbBranch(reinterpret_cast<Gen5::CommandBuffer *>(&branch_dcb),
1, 0, &condition, 0, 0, 0, nullptr, 0,
3, else_commands.data(), else_commands.size()) ==
patched_branch.data() && branch_dcb.cursor_up == branch_dcb.top,
"branch size did not match the emitted command buffer");
patched_branch[8] = 3;
patched_branch[10] = 0xc5a00000u;
const auto unpatched = patched_branch;
Require(name, "patched indirect context branch",
Gen5::AgcBranchPatchSetThenTarget(patched_branch.data(), 2,
cx_packet.data(), cx_packet.size()) == 0 &&
(patched_branch[8] & 3u) == 3u &&
patched_branch[10] == 0xe5a00005u &&
std::equal(patched_branch.begin(), patched_branch.begin() + 8,
unpatched.begin()) &&
std::equal(patched_branch.begin() + 11, patched_branch.end(),
unpatched.begin() + 11),
"branch target patch lost reserved fields or changed the condition/else target");
Pm4Execution patched_execution;
Require(name, "patched branch execution",
processor.Process(patched_execution, patched_branch) == Pm4ProcessResult::Complete &&
processor.GetCtx().GetRenderTargetMask() == cx_register.value,
"patched branch did not fetch and apply its indirect context registers");
patched_branch[0] = KYTY_PM4(14, Pm4::IT_NOP, 0);
const auto mismatched = patched_branch;
Require(name, "branch packet mismatch",
Gen5::AgcBranchPatchSetThenTarget(patched_branch.data(), 0,
then_commands.data(), then_commands.size()) ==
static_cast<int>(0x8a6c000cu) && patched_branch == mismatched,
"branch patch accepted or changed a different packet type");
// This stream exceeds native recursion capacity, while chains need one fetcher cursor.
std::vector<std::array<uint32_t, 4>> links(65536);
std::span<const uint32_t> target = then_commands;