mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
agc: implement branch target patching and packet size queries
This commit is contained in:
1 parent
a31e2cd361
commit
3ae5a9b70a
4 files changed
+102
-13
No files matched your search
+44
-13
@@ -830,6 +830,8 @@ enum class RegIndirectPacket : uint32_t {
|
||||
Uc,
|
||||
};
|
||||
|
||||
static constexpr uint32_t RegIndirectPacketSizeDw = 5;
|
||||
|
||||
static uint32_t reg_indirect_native_op(RegIndirectPacket type) {
|
||||
switch (type) {
|
||||
case RegIndirectPacket::Cx: return Pm4::IT_SET_CONTEXT_REG_INDIRECT;
|
||||
@@ -853,7 +855,7 @@ static uint32_t reg_indirect_pm4_r(RegIndirectPacket type) {
|
||||
|
||||
static void reg_indirect_write_packet(uint32_t* cmd, uint64_t vaddr, uint32_t num_regs,
|
||||
RegIndirectPacket type) {
|
||||
cmd[0] = KYTY_PM4(5, reg_indirect_native_op(type), reg_indirect_pm4_r(type));
|
||||
cmd[0] = KYTY_PM4(RegIndirectPacketSizeDw, reg_indirect_native_op(type), reg_indirect_pm4_r(type));
|
||||
cmd[1] = static_cast<uint32_t>(vaddr) & 0xfffffffcu;
|
||||
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
||||
cmd[3] = 0x80000000u;
|
||||
@@ -1789,6 +1791,33 @@ uint32_t KYTY_SYSV_ABI AgcCbDispatchGetSize() {
|
||||
return 20;
|
||||
}
|
||||
|
||||
static constexpr uint32_t BranchPacketSizeDw = 14;
|
||||
|
||||
static void write_branch_target(uint32_t* words, uint64_t address, uint8_t cache_policy,
|
||||
uint32_t size_in_dwords) {
|
||||
words[0] = (words[0] & 0x3u) | (static_cast<uint32_t>(address) & ~0x3u);
|
||||
words[1] = static_cast<uint32_t>(address >> 32u);
|
||||
words[2] = (words[2] & 0xcff00000u) | (size_in_dwords & 0xfffffu) |
|
||||
((static_cast<uint32_t>(cache_policy) & 0x3u) << 28u);
|
||||
}
|
||||
|
||||
uint64_t KYTY_SYSV_ABI AgcCbBranchGetSize() {
|
||||
PRINT_NAME();
|
||||
return BranchPacketSizeDw * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI AgcBranchPatchSetThenTarget(uint32_t* cmd, uint8_t cache_policy,
|
||||
const volatile uint32_t* target,
|
||||
uint32_t size_in_dwords) {
|
||||
PRINT_NAME();
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
if (((cmd[0] >> 8u) & 0xffu) != Pm4::IT_INDIRECT_BUFFER) {
|
||||
return GRAPHICS5_ERROR_INVALID_PACKET;
|
||||
}
|
||||
write_branch_target(cmd + 8, reinterpret_cast<uint64_t>(target), cache_policy, size_in_dwords);
|
||||
return OK;
|
||||
}
|
||||
|
||||
uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t compare_function,
|
||||
const volatile uint64_t* compare_addr, uint64_t mask,
|
||||
uint64_t reference, uint8_t cache_policy1,
|
||||
@@ -1814,7 +1843,7 @@ uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t co
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
||||
|
||||
auto* cmd = buf->AllocateDW(14);
|
||||
auto* cmd = buf->AllocateDW(BranchPacketSizeDw);
|
||||
|
||||
if (cmd == nullptr) {
|
||||
LOGF_COLOR(Log::Color::Red, "\t failed to allocate branch packet\n");
|
||||
@@ -1825,7 +1854,7 @@ uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t co
|
||||
const auto then_vaddr = reinterpret_cast<uint64_t>(buffer1);
|
||||
const auto else_vaddr = reinterpret_cast<uint64_t>(buffer2);
|
||||
|
||||
cmd[0] = KYTY_PM4(14, Pm4::IT_INDIRECT_BUFFER, 0u);
|
||||
cmd[0] = KYTY_PM4(BranchPacketSizeDw, Pm4::IT_INDIRECT_BUFFER, 0u);
|
||||
cmd[1] = (mode & 0x3u) | ((static_cast<uint32_t>(compare_function) & 0x7u) << 8u);
|
||||
cmd[2] = static_cast<uint32_t>(compare_vaddr & 0xfffffff8u);
|
||||
cmd[3] = static_cast<uint32_t>((compare_vaddr >> 32u) & 0xffffffffu);
|
||||
@@ -1833,12 +1862,9 @@ uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t co
|
||||
cmd[5] = static_cast<uint32_t>((mask >> 32u) & 0xffffffffu);
|
||||
cmd[6] = static_cast<uint32_t>(reference & 0xffffffffu);
|
||||
cmd[7] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
||||
cmd[8] = static_cast<uint32_t>(then_vaddr & 0xfffffffcu);
|
||||
cmd[9] = static_cast<uint32_t>((then_vaddr >> 32u) & 0xffffffffu);
|
||||
cmd[10] = (size_in_dwords1 & 0xfffffu) | ((static_cast<uint32_t>(cache_policy1) & 0x3u) << 28u);
|
||||
cmd[11] = static_cast<uint32_t>(else_vaddr & 0xfffffffcu);
|
||||
cmd[12] = static_cast<uint32_t>((else_vaddr >> 32u) & 0xffffffffu);
|
||||
cmd[13] = (size_in_dwords2 & 0xfffffu) | ((static_cast<uint32_t>(cache_policy2) & 0x3u) << 28u);
|
||||
std::fill(cmd + 8, cmd + BranchPacketSizeDw, 0u);
|
||||
write_branch_target(cmd + 8, then_vaddr, cache_policy1, size_in_dwords1);
|
||||
write_branch_target(cmd + 11, else_vaddr, cache_policy2, size_in_dwords2);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
@@ -2353,7 +2379,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer*
|
||||
|
||||
buf->DbgDump();
|
||||
|
||||
auto* cmd = buf->AllocateDW(5);
|
||||
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
|
||||
@@ -2364,6 +2390,11 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer*
|
||||
return cmd;
|
||||
}
|
||||
|
||||
uint64_t KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirectGetSize() {
|
||||
PRINT_NAME();
|
||||
return RegIndirectPacketSizeDw * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
||||
const volatile ShaderRegister* regs,
|
||||
uint32_t num_regs) {
|
||||
@@ -2377,7 +2408,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer*
|
||||
|
||||
buf->DbgDump();
|
||||
|
||||
auto* cmd = buf->AllocateDW(5);
|
||||
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
|
||||
@@ -2391,7 +2422,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer*
|
||||
uint64_t KYTY_SYSV_ABI AgcDcbSetShRegistersIndirectGetSize() {
|
||||
PRINT_NAME();
|
||||
|
||||
return 5u * sizeof(uint32_t);
|
||||
return RegIndirectPacketSizeDw * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer* buf,
|
||||
@@ -2407,7 +2438,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer*
|
||||
|
||||
buf->DbgDump();
|
||||
|
||||
auto* cmd = buf->AllocateDW(5);
|
||||
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
|
||||
|
||||
@@ -101,6 +101,10 @@ uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t co
|
||||
const volatile uint32_t* buffer1, uint32_t size_in_dwords1,
|
||||
uint8_t cache_policy2, const volatile uint32_t* buffer2,
|
||||
uint32_t size_in_dwords2);
|
||||
uint64_t KYTY_SYSV_ABI AgcCbBranchGetSize();
|
||||
int KYTY_SYSV_ABI AgcBranchPatchSetThenTarget(uint32_t* cmd, uint8_t cache_policy,
|
||||
const volatile uint32_t* target,
|
||||
uint32_t size_in_dwords);
|
||||
uint32_t* KYTY_SYSV_ABI AgcCbSetShRegisterRangeDirect(CommandBuffer* buf, uint32_t offset,
|
||||
const uint32_t* values, uint32_t num_values);
|
||||
uint32_t KYTY_SYSV_ABI AgcCbSetShRegisterRangeDirectGetSize(uint32_t num_values);
|
||||
@@ -134,6 +138,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegisterDirect(CommandBuffer* buf, ShaderRegi
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer* buf,
|
||||
const volatile ShaderRegister* regs,
|
||||
uint32_t num_regs);
|
||||
uint64_t KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirectGetSize();
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
||||
const volatile ShaderRegister* regs,
|
||||
uint32_t num_regs);
|
||||
|
||||
@@ -59,6 +59,8 @@ LIB_DEFINE(InitAgcDriver_1) {
|
||||
LIB_FUNC("k3GhuSNmBLU", Gen5::AgcCbDispatch);
|
||||
LIB_FUNC("Abendgtz+3o", Gen5::AgcCbDispatchGetSize);
|
||||
LIB_FUNC("w1KFAHVqpaU", Gen5::AgcCbBranch);
|
||||
LIB_FUNC("uZW-mqsxkrM", Gen5::AgcCbBranchGetSize);
|
||||
LIB_FUNC("7Wa3aeJgeVU", Gen5::AgcBranchPatchSetThenTarget);
|
||||
LIB_FUNC("n2fD4A+pb+g", Gen5::AgcCbSetShRegisterRangeDirect);
|
||||
LIB_FUNC("bxGoVxpdSPQ", Gen5::AgcCbSetShRegisterRangeDirectGetSize);
|
||||
LIB_FUNC("UZbQjYAwwXM", Gen5::AgcCbSetShRegistersDirect);
|
||||
@@ -95,6 +97,7 @@ LIB_DEFINE(InitAgcDriver_1) {
|
||||
LIB_FUNC("1DeUNpRIDDA", Gen5::AgcDcbSetCxRegisterDirectGetSize);
|
||||
LIB_FUNC("w4-d0n60hdo", Gen5::AgcDcbSetUcRegisterDirect);
|
||||
LIB_FUNC("ZvwO9euwYzc", Gen5::AgcDcbSetCxRegistersIndirect);
|
||||
LIB_FUNC("GBCh3zCihoU", Gen5::AgcDcbSetCxRegistersIndirectGetSize);
|
||||
LIB_FUNC("-HOOCn0JY48", Gen5::AgcDcbSetShRegistersIndirect);
|
||||
LIB_FUNC("nNlUtdDDvZ0", Gen5::AgcDcbSetShRegistersIndirectGetSize);
|
||||
LIB_FUNC("hvUfkUIQcOE", Gen5::AgcDcbSetUcRegistersIndirect);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user