mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 22:06:59 +01:00
agc: implement branch target patching and packet size queries
This commit is contained in:
+44
-13
@@ -830,6 +830,8 @@ enum class RegIndirectPacket : uint32_t {
|
|||||||
Uc,
|
Uc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static constexpr uint32_t RegIndirectPacketSizeDw = 5;
|
||||||
|
|
||||||
static uint32_t reg_indirect_native_op(RegIndirectPacket type) {
|
static uint32_t reg_indirect_native_op(RegIndirectPacket type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case RegIndirectPacket::Cx: return Pm4::IT_SET_CONTEXT_REG_INDIRECT;
|
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,
|
static void reg_indirect_write_packet(uint32_t* cmd, uint64_t vaddr, uint32_t num_regs,
|
||||||
RegIndirectPacket type) {
|
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[1] = static_cast<uint32_t>(vaddr) & 0xfffffffcu;
|
||||||
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
cmd[2] = static_cast<uint32_t>(vaddr >> 32u);
|
||||||
cmd[3] = 0x80000000u;
|
cmd[3] = 0x80000000u;
|
||||||
@@ -1789,6 +1791,33 @@ uint32_t KYTY_SYSV_ABI AgcCbDispatchGetSize() {
|
|||||||
return 20;
|
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,
|
uint32_t* KYTY_SYSV_ABI AgcCbBranch(CommandBuffer* buf, uint8_t mode, uint8_t compare_function,
|
||||||
const volatile uint64_t* compare_addr, uint64_t mask,
|
const volatile uint64_t* compare_addr, uint64_t mask,
|
||||||
uint64_t reference, uint8_t cache_policy1,
|
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);
|
EXIT_NOT_IMPLEMENTED(buf == nullptr);
|
||||||
|
|
||||||
auto* cmd = buf->AllocateDW(14);
|
auto* cmd = buf->AllocateDW(BranchPacketSizeDw);
|
||||||
|
|
||||||
if (cmd == nullptr) {
|
if (cmd == nullptr) {
|
||||||
LOGF_COLOR(Log::Color::Red, "\t failed to allocate branch packet\n");
|
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 then_vaddr = reinterpret_cast<uint64_t>(buffer1);
|
||||||
const auto else_vaddr = reinterpret_cast<uint64_t>(buffer2);
|
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[1] = (mode & 0x3u) | ((static_cast<uint32_t>(compare_function) & 0x7u) << 8u);
|
||||||
cmd[2] = static_cast<uint32_t>(compare_vaddr & 0xfffffff8u);
|
cmd[2] = static_cast<uint32_t>(compare_vaddr & 0xfffffff8u);
|
||||||
cmd[3] = static_cast<uint32_t>((compare_vaddr >> 32u) & 0xffffffffu);
|
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[5] = static_cast<uint32_t>((mask >> 32u) & 0xffffffffu);
|
||||||
cmd[6] = static_cast<uint32_t>(reference & 0xffffffffu);
|
cmd[6] = static_cast<uint32_t>(reference & 0xffffffffu);
|
||||||
cmd[7] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
cmd[7] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
||||||
cmd[8] = static_cast<uint32_t>(then_vaddr & 0xfffffffcu);
|
std::fill(cmd + 8, cmd + BranchPacketSizeDw, 0u);
|
||||||
cmd[9] = static_cast<uint32_t>((then_vaddr >> 32u) & 0xffffffffu);
|
write_branch_target(cmd + 8, then_vaddr, cache_policy1, size_in_dwords1);
|
||||||
cmd[10] = (size_in_dwords1 & 0xfffffu) | ((static_cast<uint32_t>(cache_policy1) & 0x3u) << 28u);
|
write_branch_target(cmd + 11, else_vaddr, cache_policy2, size_in_dwords2);
|
||||||
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);
|
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
@@ -2353,7 +2379,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer*
|
|||||||
|
|
||||||
buf->DbgDump();
|
buf->DbgDump();
|
||||||
|
|
||||||
auto* cmd = buf->AllocateDW(5);
|
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||||
|
|
||||||
@@ -2364,6 +2390,11 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer*
|
|||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirectGetSize() {
|
||||||
|
PRINT_NAME();
|
||||||
|
return RegIndirectPacketSizeDw * sizeof(uint32_t);
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
||||||
const volatile ShaderRegister* regs,
|
const volatile ShaderRegister* regs,
|
||||||
uint32_t num_regs) {
|
uint32_t num_regs) {
|
||||||
@@ -2377,7 +2408,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer*
|
|||||||
|
|
||||||
buf->DbgDump();
|
buf->DbgDump();
|
||||||
|
|
||||||
auto* cmd = buf->AllocateDW(5);
|
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||||
|
|
||||||
@@ -2391,7 +2422,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer*
|
|||||||
uint64_t KYTY_SYSV_ABI AgcDcbSetShRegistersIndirectGetSize() {
|
uint64_t KYTY_SYSV_ABI AgcDcbSetShRegistersIndirectGetSize() {
|
||||||
PRINT_NAME();
|
PRINT_NAME();
|
||||||
|
|
||||||
return 5u * sizeof(uint32_t);
|
return RegIndirectPacketSizeDw * sizeof(uint32_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer* buf,
|
uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer* buf,
|
||||||
@@ -2407,7 +2438,7 @@ uint32_t* KYTY_SYSV_ABI AgcDcbSetUcRegistersIndirect(CommandBuffer*
|
|||||||
|
|
||||||
buf->DbgDump();
|
buf->DbgDump();
|
||||||
|
|
||||||
auto* cmd = buf->AllocateDW(5);
|
auto* cmd = buf->AllocateDW(RegIndirectPacketSizeDw);
|
||||||
|
|
||||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
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,
|
const volatile uint32_t* buffer1, uint32_t size_in_dwords1,
|
||||||
uint8_t cache_policy2, const volatile uint32_t* buffer2,
|
uint8_t cache_policy2, const volatile uint32_t* buffer2,
|
||||||
uint32_t size_in_dwords2);
|
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,
|
uint32_t* KYTY_SYSV_ABI AgcCbSetShRegisterRangeDirect(CommandBuffer* buf, uint32_t offset,
|
||||||
const uint32_t* values, uint32_t num_values);
|
const uint32_t* values, uint32_t num_values);
|
||||||
uint32_t KYTY_SYSV_ABI AgcCbSetShRegisterRangeDirectGetSize(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,
|
uint32_t* KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirect(CommandBuffer* buf,
|
||||||
const volatile ShaderRegister* regs,
|
const volatile ShaderRegister* regs,
|
||||||
uint32_t num_regs);
|
uint32_t num_regs);
|
||||||
|
uint64_t KYTY_SYSV_ABI AgcDcbSetCxRegistersIndirectGetSize();
|
||||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
uint32_t* KYTY_SYSV_ABI AgcDcbSetShRegistersIndirect(CommandBuffer* buf,
|
||||||
const volatile ShaderRegister* regs,
|
const volatile ShaderRegister* regs,
|
||||||
uint32_t num_regs);
|
uint32_t num_regs);
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ LIB_DEFINE(InitAgcDriver_1) {
|
|||||||
LIB_FUNC("k3GhuSNmBLU", Gen5::AgcCbDispatch);
|
LIB_FUNC("k3GhuSNmBLU", Gen5::AgcCbDispatch);
|
||||||
LIB_FUNC("Abendgtz+3o", Gen5::AgcCbDispatchGetSize);
|
LIB_FUNC("Abendgtz+3o", Gen5::AgcCbDispatchGetSize);
|
||||||
LIB_FUNC("w1KFAHVqpaU", Gen5::AgcCbBranch);
|
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("n2fD4A+pb+g", Gen5::AgcCbSetShRegisterRangeDirect);
|
||||||
LIB_FUNC("bxGoVxpdSPQ", Gen5::AgcCbSetShRegisterRangeDirectGetSize);
|
LIB_FUNC("bxGoVxpdSPQ", Gen5::AgcCbSetShRegisterRangeDirectGetSize);
|
||||||
LIB_FUNC("UZbQjYAwwXM", Gen5::AgcCbSetShRegistersDirect);
|
LIB_FUNC("UZbQjYAwwXM", Gen5::AgcCbSetShRegistersDirect);
|
||||||
@@ -95,6 +97,7 @@ LIB_DEFINE(InitAgcDriver_1) {
|
|||||||
LIB_FUNC("1DeUNpRIDDA", Gen5::AgcDcbSetCxRegisterDirectGetSize);
|
LIB_FUNC("1DeUNpRIDDA", Gen5::AgcDcbSetCxRegisterDirectGetSize);
|
||||||
LIB_FUNC("w4-d0n60hdo", Gen5::AgcDcbSetUcRegisterDirect);
|
LIB_FUNC("w4-d0n60hdo", Gen5::AgcDcbSetUcRegisterDirect);
|
||||||
LIB_FUNC("ZvwO9euwYzc", Gen5::AgcDcbSetCxRegistersIndirect);
|
LIB_FUNC("ZvwO9euwYzc", Gen5::AgcDcbSetCxRegistersIndirect);
|
||||||
|
LIB_FUNC("GBCh3zCihoU", Gen5::AgcDcbSetCxRegistersIndirectGetSize);
|
||||||
LIB_FUNC("-HOOCn0JY48", Gen5::AgcDcbSetShRegistersIndirect);
|
LIB_FUNC("-HOOCn0JY48", Gen5::AgcDcbSetShRegistersIndirect);
|
||||||
LIB_FUNC("nNlUtdDDvZ0", Gen5::AgcDcbSetShRegistersIndirectGetSize);
|
LIB_FUNC("nNlUtdDDvZ0", Gen5::AgcDcbSetShRegistersIndirectGetSize);
|
||||||
LIB_FUNC("hvUfkUIQcOE", Gen5::AgcDcbSetUcRegistersIndirect);
|
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.
|
// This stream exceeds native recursion capacity, while chains need one fetcher cursor.
|
||||||
std::vector<std::array<uint32_t, 4>> links(65536);
|
std::vector<std::array<uint32_t, 4>> links(65536);
|
||||||
std::span<const uint32_t> target = then_commands;
|
std::span<const uint32_t> target = then_commands;
|
||||||
|
|||||||
Reference in New Issue
Block a user