mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
agc: emit native wait-on-address packets
This commit is contained in:
@@ -216,6 +216,7 @@ constexpr auto MakeOpcodeDispatchTable() {
|
||||
g_cp_op_func[Pm4::IT_COND_EXEC] = CpOpCondExec;
|
||||
g_cp_op_func[Pm4::IT_SET_PREDICATION] = CpOpSetPredication;
|
||||
g_cp_op_func[Pm4::IT_WRITE_DATA] = CpOpWriteData;
|
||||
g_cp_op_func[Pm4::IT_WAIT_REG_MEM] = CpOpWaitRegMem32;
|
||||
g_cp_op_func[Pm4::IT_INDIRECT_BUFFER] = CpOpIndirectBuffer;
|
||||
g_cp_op_func[Pm4::IT_COPY_DATA] = CpOpCopyData;
|
||||
g_cp_op_func[Pm4::IT_EVENT_WRITE] = CpOpEventWrite;
|
||||
@@ -238,6 +239,7 @@ constexpr auto MakeOpcodeDispatchTable() {
|
||||
g_cp_op_func[Pm4::IT_WAIT_ON_CE_COUNTER] = CpOpWaitOnCeCounter;
|
||||
g_cp_op_func[Pm4::IT_WAIT_ON_DE_COUNTER_DIFF] = CpOpWaitOnDeCounterDiff;
|
||||
g_cp_op_func[Pm4::IT_GET_LOD_STATS] = CpOpGetLodStats;
|
||||
g_cp_op_func[Pm4::IT_WAIT_REG_MEM_64] = CpOpWaitRegMem64;
|
||||
|
||||
return g_cp_op_func;
|
||||
}
|
||||
@@ -246,12 +248,10 @@ constexpr auto MakeCustomOpcodeDispatchTable() {
|
||||
std::array<cp_op_parser_func_t, Pm4::R_NUM> g_cp_op_custom_func {};
|
||||
|
||||
g_cp_op_custom_func[Pm4::R_DISPATCH_RESET] = CpOpDispatchReset;
|
||||
g_cp_op_custom_func[Pm4::R_WAIT_MEM_32] = CpOpWaitRegMem32;
|
||||
g_cp_op_custom_func[Pm4::R_WAIT_FLIP_DONE] = CpOpWaitFlipDone;
|
||||
g_cp_op_custom_func[Pm4::R_PUSH_MARKER] = CpOpPushMarker;
|
||||
g_cp_op_custom_func[Pm4::R_POP_MARKER] = CpOpPopMarker;
|
||||
g_cp_op_custom_func[Pm4::R_ACQUIRE_MEM] = CpOpAcquireMem;
|
||||
g_cp_op_custom_func[Pm4::R_WAIT_MEM_64] = CpOpWaitRegMem64;
|
||||
g_cp_op_custom_func[Pm4::R_FLIP] = CpOpFlip;
|
||||
g_cp_op_custom_func[Pm4::R_RELEASE_MEM] = CpOpReleaseMem;
|
||||
g_cp_op_custom_func[Pm4::R_CONTEXT_STATE] = CpOpContextState;
|
||||
|
||||
@@ -2866,6 +2866,10 @@ KYTY_CP_OP_PARSER(CpOpSetShaderReg) {
|
||||
KYTY_CP_OP_PARSER(CpOpSetUconfigReg) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
if (Gen5::AgcIsWaitUserDataPacket(cmd_id, buffer)) {
|
||||
return KYTY_PM4_LEN(cmd_id) - 1u;
|
||||
}
|
||||
|
||||
auto raw_cmd_offset = buffer[0];
|
||||
auto cmd_offset = NormalizeRegisterOffset(raw_cmd_offset);
|
||||
|
||||
@@ -2956,19 +2960,21 @@ template <typename T>
|
||||
static uint32_t CpOpWaitRegMemSized(CommandProcessor& cp, uint32_t cmd_id, const uint32_t* buffer) {
|
||||
static_assert(sizeof(T) == sizeof(uint32_t) || sizeof(T) == sizeof(uint64_t));
|
||||
|
||||
constexpr auto value_dw = static_cast<uint32_t>(sizeof(T) / sizeof(uint32_t));
|
||||
constexpr auto value_dw = static_cast<uint32_t>(sizeof(T) / sizeof(uint32_t));
|
||||
constexpr auto payload_dw = 4u + value_dw * 2u;
|
||||
constexpr auto packet_dw = payload_dw + 1u;
|
||||
constexpr auto register_id =
|
||||
(sizeof(T) == sizeof(uint32_t) ? Pm4::R_WAIT_MEM_32 : Pm4::R_WAIT_MEM_64);
|
||||
constexpr auto opcode =
|
||||
(sizeof(T) == sizeof(uint32_t) ? Pm4::IT_WAIT_REG_MEM : Pm4::IT_WAIT_REG_MEM_64);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(KYTY_PM4_R(cmd_id) != register_id);
|
||||
EXIT_NOT_IMPLEMENTED(((cmd_id >> 8u) & 0xffu) != opcode || KYTY_PM4_R(cmd_id) != 0u);
|
||||
EXIT_NOT_IMPLEMENTED(KYTY_PM4_LEN(cmd_id) != packet_dw);
|
||||
|
||||
auto* addr = reinterpret_cast<const T*>(buffer[0] | (static_cast<uint64_t>(buffer[1]) << 32u));
|
||||
auto mask = CpOpWaitRegMemReadValue<T>(buffer + 2u);
|
||||
auto ref = CpOpWaitRegMemReadValue<T>(buffer + 2u + value_dw);
|
||||
auto ctrl = buffer[2u + value_dw * 2u];
|
||||
constexpr auto address_align_mask = (sizeof(T) == sizeof(uint32_t) ? 0x3u : 0x7u);
|
||||
auto ctrl = buffer[0];
|
||||
auto* addr = reinterpret_cast<const T*>((buffer[1] & ~address_align_mask) |
|
||||
(static_cast<uint64_t>(buffer[2] & 0x3ffffu) << 32u));
|
||||
auto ref = CpOpWaitRegMemReadValue<T>(buffer + 3u);
|
||||
auto mask = CpOpWaitRegMemReadValue<T>(buffer + 3u + value_dw);
|
||||
auto poll = buffer[3u + value_dw * 2u];
|
||||
|
||||
EXIT_NOT_IMPLEMENTED((ctrl & 0x10u) == 0);
|
||||
|
||||
@@ -21,12 +21,10 @@ constexpr auto MakeRegisterNames() {
|
||||
names[R_DRAW_RESET] = "R_DRAW_RESET";
|
||||
names[R_WAIT_FLIP_DONE] = "R_WAIT_FLIP_DONE";
|
||||
names[R_DISPATCH_RESET] = "R_DISPATCH_RESET";
|
||||
names[R_WAIT_MEM_32] = "R_WAIT_MEM_32";
|
||||
names[R_PUSH_MARKER] = "R_PUSH_MARKER";
|
||||
names[R_POP_MARKER] = "R_POP_MARKER";
|
||||
names[R_ACQUIRE_MEM] = "R_ACQUIRE_MEM";
|
||||
names[R_WRITE_DATA] = "R_WRITE_DATA";
|
||||
names[R_WAIT_MEM_64] = "R_WAIT_MEM_64";
|
||||
names[R_FLIP] = "R_FLIP";
|
||||
names[R_RELEASE_MEM] = "R_RELEASE_MEM";
|
||||
names[R_DMA_DATA] = "R_DMA_DATA";
|
||||
@@ -62,6 +60,7 @@ constexpr auto MakeOpcodeNames() {
|
||||
names[IT_WRITE_DATA] = "IT_WRITE_DATA";
|
||||
names[IT_MEM_SEMAPHORE] = "IT_MEM_SEMAPHORE";
|
||||
names[IT_DRAW_INDEX_INDIRECT_MULTI] = "IT_DRAW_INDEX_INDIRECT_MULTI";
|
||||
names[IT_WAIT_REG_MEM] = "IT_WAIT_REG_MEM";
|
||||
names[IT_INDIRECT_BUFFER] = "IT_INDIRECT_BUFFER";
|
||||
names[IT_COPY_DATA] = "IT_COPY_DATA";
|
||||
names[IT_CP_DMA] = "IT_CP_DMA";
|
||||
@@ -91,6 +90,7 @@ constexpr auto MakeOpcodeNames() {
|
||||
names[IT_DISPATCH_DRAW_PREAMBLE] = "IT_DISPATCH_DRAW_PREAMBLE";
|
||||
names[IT_DISPATCH_DRAW] = "IT_DISPATCH_DRAW";
|
||||
names[IT_GET_LOD_STATS] = "IT_GET_LOD_STATS";
|
||||
names[IT_WAIT_REG_MEM_64] = "IT_WAIT_REG_MEM_64";
|
||||
names[IT_SET_CONTEXT_REG_INDIRECT] = "IT_SET_CONTEXT_REG_INDIRECT";
|
||||
return names;
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ constexpr uint32_t IT_WRITE_DATA = 0x37;
|
||||
constexpr uint32_t IT_MEM_SEMAPHORE = 0x39;
|
||||
constexpr uint32_t IT_DRAW_INDEX_INDIRECT_MULTI = 0x38;
|
||||
constexpr uint32_t IT_DISPATCH_DRAW_PREAMBLE = 0x3A;
|
||||
constexpr uint32_t IT_WAIT_REG_MEM = 0x3C;
|
||||
constexpr uint32_t IT_INDIRECT_BUFFER = 0x3F;
|
||||
constexpr uint32_t IT_COPY_DATA = 0x40;
|
||||
constexpr uint32_t IT_CP_DMA = 0x41;
|
||||
@@ -70,6 +71,7 @@ constexpr uint32_t IT_WAIT_ON_CE_COUNTER = 0x86;
|
||||
constexpr uint32_t IT_WAIT_ON_DE_COUNTER_DIFF = 0x88;
|
||||
constexpr uint32_t IT_DISPATCH_DRAW = 0x8D;
|
||||
constexpr uint32_t IT_GET_LOD_STATS = 0x8E;
|
||||
constexpr uint32_t IT_WAIT_REG_MEM_64 = 0x93;
|
||||
constexpr uint32_t IT_SET_CONTEXT_REG_INDIRECT = 0x9F;
|
||||
|
||||
/* Custom codes. Implemented via IT_NOP */
|
||||
@@ -78,12 +80,10 @@ constexpr uint32_t R_ZERO = 0x00;
|
||||
constexpr uint32_t R_DRAW_RESET = 0x05;
|
||||
constexpr uint32_t R_WAIT_FLIP_DONE = 0x06;
|
||||
constexpr uint32_t R_DISPATCH_RESET = 0x09;
|
||||
constexpr uint32_t R_WAIT_MEM_32 = 0x0A;
|
||||
constexpr uint32_t R_PUSH_MARKER = 0x0B;
|
||||
constexpr uint32_t R_POP_MARKER = 0x0C;
|
||||
constexpr uint32_t R_ACQUIRE_MEM = 0x14;
|
||||
constexpr uint32_t R_WRITE_DATA = 0x15;
|
||||
constexpr uint32_t R_WAIT_MEM_64 = 0x16;
|
||||
constexpr uint32_t R_FLIP = 0x17;
|
||||
constexpr uint32_t R_RELEASE_MEM = 0x18;
|
||||
constexpr uint32_t R_DMA_DATA = 0x19;
|
||||
|
||||
+93
-42
@@ -3705,6 +3705,33 @@ uint32_t* KYTY_SYSV_ABI AgcDcbGetLodStats(CommandBuffer* buf, uint8_t cache_poli
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_REGISTER = 0x342u;
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_BEGIN_32_TAG = 0xc8010000u;
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_BEGIN_64_TAG = 0xc8020000u;
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_END_TAG = 0xc8000000u;
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_BEGIN_DW = 4u;
|
||||
static constexpr uint32_t AGC_WAIT_USER_DATA_END_DW = 3u;
|
||||
|
||||
static uint32_t* get_agc_wait_packet(uint32_t* cmd) {
|
||||
if (cmd == nullptr || KYTY_PM4_LEN(cmd[0]) != AGC_WAIT_USER_DATA_BEGIN_DW ||
|
||||
!AgcIsWaitUserDataPacket(cmd[0], cmd + 1)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* wait = cmd + AGC_WAIT_USER_DATA_BEGIN_DW;
|
||||
const auto op = (wait[0] >> 8u) & 0xffu;
|
||||
const auto len = KYTY_PM4_LEN(wait[0]);
|
||||
const auto tag = cmd[2] & 0xffff0000u;
|
||||
if (KYTY_PM4_R(wait[0]) != 0u ||
|
||||
!((op == Pm4::IT_WAIT_REG_MEM && len == 7u && tag == AGC_WAIT_USER_DATA_BEGIN_32_TAG) ||
|
||||
(op == Pm4::IT_WAIT_REG_MEM_64 && len == 9u &&
|
||||
tag == AGC_WAIT_USER_DATA_BEGIN_64_TAG))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return wait;
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI AgcWaitRegMemPatchAddress(uint32_t* cmd, const volatile void* address) {
|
||||
PRINT_NAME();
|
||||
|
||||
@@ -3712,21 +3739,20 @@ int KYTY_SYSV_ABI AgcWaitRegMemPatchAddress(uint32_t* cmd, const volatile void*
|
||||
"\t address = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(cmd), reinterpret_cast<uint64_t>(address));
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
|
||||
auto vaddr = reinterpret_cast<uint64_t>(address);
|
||||
auto op = (cmd[0] >> 8u) & 0xffu;
|
||||
|
||||
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_32) {
|
||||
cmd[1] = static_cast<uint32_t>(vaddr) & ~0x3u;
|
||||
cmd[2] = static_cast<uint32_t>(vaddr >> 32u) & 0x3ffffu;
|
||||
} else if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_64) {
|
||||
cmd[1] = static_cast<uint32_t>(vaddr) & ~0x7u;
|
||||
cmd[2] = static_cast<uint32_t>(vaddr >> 32u) & 0x3ffffu;
|
||||
} else {
|
||||
EXIT("unsupported waitOnAddress packet for address patch: 0x%08" PRIx32 "\n", cmd[0]);
|
||||
auto* wait = get_agc_wait_packet(cmd);
|
||||
if (wait == nullptr) {
|
||||
return GRAPHICS5_ERROR_INVALID_PACKET;
|
||||
}
|
||||
|
||||
const auto vaddr = reinterpret_cast<uint64_t>(address);
|
||||
const auto op = (wait[0] >> 8u) & 0xffu;
|
||||
const auto align_mask = (op == Pm4::IT_WAIT_REG_MEM ? 0x3u : 0x7u);
|
||||
cmd[2] = (cmd[2] & 0xffff0000u) | static_cast<uint32_t>((vaddr >> 32u) & 0xffffu);
|
||||
cmd[3] = static_cast<uint32_t>(vaddr);
|
||||
wait[2] = (wait[2] & align_mask) | (static_cast<uint32_t>(vaddr) & ~align_mask);
|
||||
wait[3] = (wait[3] & 0xfffc0000u) |
|
||||
(static_cast<uint32_t>(vaddr >> 32u) & 0x3ffffu);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -3737,19 +3763,14 @@ int KYTY_SYSV_ABI AgcWaitRegMemPatchReference(uint32_t* cmd, uint64_t reference)
|
||||
"\t reference = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(cmd), reference);
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd == nullptr);
|
||||
|
||||
auto op = (cmd[0] >> 8u) & 0xffu;
|
||||
|
||||
if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_32) {
|
||||
cmd[4] = static_cast<uint32_t>(reference & 0xffffffffu);
|
||||
} else if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd[0]) == Pm4::R_WAIT_MEM_64) {
|
||||
cmd[5] = static_cast<uint32_t>(reference & 0xffffffffu);
|
||||
cmd[6] = static_cast<uint32_t>((reference >> 32u) & 0xffffffffu);
|
||||
} else {
|
||||
EXIT("unsupported waitOnAddress packet for reference patch: 0x%08" PRIx32 "\n", cmd[0]);
|
||||
auto* wait = get_agc_wait_packet(cmd);
|
||||
if (wait == nullptr) {
|
||||
return GRAPHICS5_ERROR_INVALID_PACKET;
|
||||
}
|
||||
|
||||
// The native patch helper changes only the low reference DWORD for both packet sizes.
|
||||
wait[4] = static_cast<uint32_t>(reference);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
@@ -3837,6 +3858,22 @@ static uint32_t wait_reg_mem64_control(uint8_t compare_function, uint8_t op, uin
|
||||
((static_cast<uint32_t>(cache_policy) & 0x3u) << 25u);
|
||||
}
|
||||
|
||||
bool AgcIsWaitUserDataPacket(uint32_t cmd_id, const uint32_t* payload) {
|
||||
if (payload == nullptr || ((cmd_id >> 8u) & 0xffu) != Pm4::IT_SET_UCONFIG_REG ||
|
||||
KYTY_PM4_R(cmd_id) != 1u || payload[0] != AGC_WAIT_USER_DATA_REGISTER) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto size_dw = KYTY_PM4_LEN(cmd_id);
|
||||
if (size_dw != AGC_WAIT_USER_DATA_BEGIN_DW && size_dw != AGC_WAIT_USER_DATA_END_DW) {
|
||||
return false;
|
||||
}
|
||||
const auto tag = payload[1] & 0xffff0000u;
|
||||
return (size_dw == AGC_WAIT_USER_DATA_BEGIN_DW &&
|
||||
(tag == AGC_WAIT_USER_DATA_BEGIN_32_TAG || tag == AGC_WAIT_USER_DATA_BEGIN_64_TAG)) ||
|
||||
(size_dw == AGC_WAIT_USER_DATA_END_DW && payload[1] == AGC_WAIT_USER_DATA_END_TAG);
|
||||
}
|
||||
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbWaitRegMem(CommandBuffer* buf, uint8_t size, uint8_t compare_function,
|
||||
uint8_t op, uint8_t cache_policy,
|
||||
const volatile void* address, uint64_t reference,
|
||||
@@ -3872,39 +3909,53 @@ uint32_t* KYTY_SYSV_ABI AgcDcbWaitRegMem(CommandBuffer* buf, uint8_t size, uint8
|
||||
auto address_value = reinterpret_cast<uint64_t>(address);
|
||||
bool wait32 = (size == 0);
|
||||
auto poll = wait_reg_mem_poll_cycles_to_packet(poll_cycles);
|
||||
const auto wait_dw = wait32 ? 7u : 9u;
|
||||
const auto total_dw = AGC_WAIT_USER_DATA_BEGIN_DW + wait_dw + AGC_WAIT_USER_DATA_END_DW;
|
||||
|
||||
auto* cmd = buf->AllocateDW(wait32 ? 7 : 9);
|
||||
auto* cmd = buf->AllocateDW(total_dw);
|
||||
|
||||
if (cmd == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
cmd[0] = KYTY_PM4(AGC_WAIT_USER_DATA_BEGIN_DW, Pm4::IT_SET_UCONFIG_REG, 1u);
|
||||
cmd[1] = AGC_WAIT_USER_DATA_REGISTER;
|
||||
cmd[2] = (wait32 ? AGC_WAIT_USER_DATA_BEGIN_32_TAG : AGC_WAIT_USER_DATA_BEGIN_64_TAG) |
|
||||
static_cast<uint32_t>((address_value >> 32u) & 0xffffu);
|
||||
cmd[3] = static_cast<uint32_t>(address_value);
|
||||
|
||||
auto* wait = cmd + AGC_WAIT_USER_DATA_BEGIN_DW;
|
||||
auto* end = wait + wait_dw;
|
||||
end[0] = KYTY_PM4(AGC_WAIT_USER_DATA_END_DW, Pm4::IT_SET_UCONFIG_REG, 1u);
|
||||
end[1] = AGC_WAIT_USER_DATA_REGISTER;
|
||||
end[2] = AGC_WAIT_USER_DATA_END_TAG;
|
||||
|
||||
if (wait32) {
|
||||
cmd[0] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_MEM_32);
|
||||
cmd[1] = static_cast<uint32_t>(address_value) & ~0x3u;
|
||||
cmd[2] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
||||
cmd[3] = static_cast<uint32_t>(mask & 0xffffffffu);
|
||||
cmd[4] = static_cast<uint32_t>(reference & 0xffffffffu);
|
||||
cmd[5] = wait_reg_mem32_control(compare_function, op, cache_policy);
|
||||
cmd[6] = poll;
|
||||
wait[0] = KYTY_PM4(7, Pm4::IT_WAIT_REG_MEM, 0u);
|
||||
wait[1] = wait_reg_mem32_control(compare_function, op, cache_policy);
|
||||
wait[2] = static_cast<uint32_t>(address_value) & ~0x3u;
|
||||
wait[3] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
||||
wait[4] = static_cast<uint32_t>(reference);
|
||||
wait[5] = static_cast<uint32_t>(mask);
|
||||
wait[6] = poll;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
cmd[0] = KYTY_PM4(9, Pm4::IT_NOP, Pm4::R_WAIT_MEM_64);
|
||||
cmd[1] = static_cast<uint32_t>(address_value) & ~0x7u;
|
||||
cmd[2] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
||||
cmd[3] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(mask) & 0xffffffffu);
|
||||
cmd[4] = static_cast<uint32_t>((reinterpret_cast<uint64_t>(mask) >> 32u) & 0xffffffffu);
|
||||
cmd[5] = static_cast<uint32_t>(reinterpret_cast<uint64_t>(reference) & 0xffffffffu);
|
||||
cmd[6] = static_cast<uint32_t>((reinterpret_cast<uint64_t>(reference) >> 32u) & 0xffffffffu);
|
||||
cmd[7] = wait_reg_mem64_control(compare_function, op, cache_policy);
|
||||
cmd[8] = poll;
|
||||
wait[0] = KYTY_PM4(9, Pm4::IT_WAIT_REG_MEM_64, 0u);
|
||||
wait[1] = wait_reg_mem64_control(compare_function, op, cache_policy);
|
||||
wait[2] = static_cast<uint32_t>(address_value) & ~0x7u;
|
||||
wait[3] = static_cast<uint32_t>(address_value >> 32u) & 0x3ffffu;
|
||||
wait[4] = static_cast<uint32_t>(reference);
|
||||
wait[5] = static_cast<uint32_t>(reference >> 32u);
|
||||
wait[6] = static_cast<uint32_t>(mask);
|
||||
wait[7] = static_cast<uint32_t>(mask >> 32u);
|
||||
wait[8] = poll;
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
uint32_t KYTY_SYSV_ABI AgcDcbWaitOnAddressGetSize(uint32_t size) {
|
||||
uint64_t KYTY_SYSV_ABI AgcDcbWaitOnAddressGetSize(uint32_t size) {
|
||||
PRINT_NAME();
|
||||
|
||||
switch (size) {
|
||||
|
||||
+2
-1
@@ -270,7 +270,8 @@ uint32_t* KYTY_SYSV_ABI AgcDcbWaitRegMem(CommandBuffer* buf, uint8_t size, uint8
|
||||
uint8_t op, uint8_t cache_policy,
|
||||
const volatile void* address, uint64_t reference,
|
||||
uint64_t mask, uint32_t poll_cycles);
|
||||
uint32_t KYTY_SYSV_ABI AgcDcbWaitOnAddressGetSize(uint32_t size);
|
||||
uint64_t KYTY_SYSV_ABI AgcDcbWaitOnAddressGetSize(uint32_t size);
|
||||
bool AgcIsWaitUserDataPacket(uint32_t cmd_id, const uint32_t* payload);
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbSetMarker(CommandBuffer* buf, const char* str, uint32_t color);
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbPushMarker(CommandBuffer* buf, const char* str, uint32_t color);
|
||||
uint32_t* KYTY_SYSV_ABI AgcDcbPopMarker(CommandBuffer* buf);
|
||||
|
||||
@@ -2035,12 +2035,12 @@ public:
|
||||
commands[2] = static_cast<uint32_t>(address(&prefix));
|
||||
commands[3] = static_cast<uint32_t>(address(&prefix) >> 32u);
|
||||
commands[4] = 11;
|
||||
commands[5] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_MEM_32);
|
||||
commands[6] = static_cast<uint32_t>(address(&label));
|
||||
commands[7] = static_cast<uint32_t>(address(&label) >> 32u);
|
||||
commands[8] = UINT32_MAX;
|
||||
commands[5] = KYTY_PM4(7, Pm4::IT_WAIT_REG_MEM, 0);
|
||||
commands[6] = 0x10u | 3u;
|
||||
commands[7] = static_cast<uint32_t>(address(&label));
|
||||
commands[8] = static_cast<uint32_t>(address(&label) >> 32u);
|
||||
commands[9] = 1;
|
||||
commands[10] = 0x10u | 3u;
|
||||
commands[10] = UINT32_MAX;
|
||||
commands[12] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[13] = 0;
|
||||
commands[14] = static_cast<uint32_t>(address(&suffix));
|
||||
@@ -22184,24 +22184,159 @@ void CheckPm4PolygonOffsetRegisters(RenderContext &renderer) {
|
||||
std::printf("[host] %-32s ok\n", "Pm4PolygonOffset");
|
||||
}
|
||||
|
||||
struct AgcCommandBufferLayout {
|
||||
using Callback = KYTY_SYSV_ABI bool (*)(Gen5::CommandBuffer *, uint32_t,
|
||||
void *);
|
||||
|
||||
uint32_t *bottom;
|
||||
uint32_t *top;
|
||||
uint32_t *cursor_up;
|
||||
uint32_t *cursor_down;
|
||||
Callback callback;
|
||||
void *user_data;
|
||||
uint32_t reserved_dw;
|
||||
};
|
||||
static_assert(offsetof(AgcCommandBufferLayout, cursor_up) == 0x10);
|
||||
static_assert(offsetof(AgcCommandBufferLayout, reserved_dw) == 0x30);
|
||||
|
||||
void CheckAgcWaitPackets(RenderContext &renderer) {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer);
|
||||
constexpr auto packet_mismatch = static_cast<int>(0x8a6c000cu);
|
||||
const auto execute = [&](uint32_t *packet, uint32_t size_dw) {
|
||||
Pm4Execution execution;
|
||||
return processor.Process(execution, packet, size_dw) ==
|
||||
Pm4ProcessResult::Complete;
|
||||
};
|
||||
|
||||
alignas(8) uint32_t label32 = 0x11223344u;
|
||||
std::array<uint32_t, 16> packet32{};
|
||||
AgcCommandBufferLayout dcb32{packet32.data(),
|
||||
packet32.data() + packet32.size(),
|
||||
packet32.data(),
|
||||
packet32.data() + packet32.size(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
0};
|
||||
const auto address32 = reinterpret_cast<uint64_t>(&label32);
|
||||
auto *emitted32 = Gen5::AgcDcbWaitRegMem(
|
||||
reinterpret_cast<Gen5::CommandBuffer *>(&dcb32), 0, 3, 0, 0,
|
||||
&label32, label32, UINT32_MAX, 400);
|
||||
Require(
|
||||
"AgcWaitPackets", "native 32-bit packet",
|
||||
Gen5::AgcDcbWaitOnAddressGetSize(0) == 56 &&
|
||||
emitted32 == packet32.data() &&
|
||||
dcb32.cursor_up == packet32.data() + 14 &&
|
||||
packet32[0] == 0xc0027904u && packet32[1] == 0x342u &&
|
||||
packet32[2] ==
|
||||
(0xc8010000u |
|
||||
(static_cast<uint32_t>(address32 >> 32u) & 0xffffu)) &&
|
||||
packet32[3] == static_cast<uint32_t>(address32) &&
|
||||
packet32[4] == 0xc0053c00u && packet32[5] == 0x13u &&
|
||||
packet32[6] == (static_cast<uint32_t>(address32) & ~0x3u) &&
|
||||
packet32[7] ==
|
||||
(static_cast<uint32_t>(address32 >> 32u) & 0x3ffffu) &&
|
||||
packet32[8] == label32 && packet32[9] == UINT32_MAX &&
|
||||
packet32[10] == 25u && packet32[11] == 0xc0017904u &&
|
||||
packet32[12] == 0x342u && packet32[13] == 0xc8000000u &&
|
||||
execute(packet32.data(), 14),
|
||||
"32-bit waitOnAddress stream differs from native AGC");
|
||||
|
||||
alignas(8) uint32_t patched_label32 = 0xaabbccddu;
|
||||
const auto patched_address32 = reinterpret_cast<uint64_t>(&patched_label32);
|
||||
packet32[6] |= 0x2u;
|
||||
packet32[7] |= 0xa5a40000u;
|
||||
Require(
|
||||
"AgcWaitPackets", "native 32-bit patch",
|
||||
Gen5::AgcWaitRegMemPatchAddress(packet32.data(), &patched_label32) == 0 &&
|
||||
Gen5::AgcWaitRegMemPatchReference(packet32.data(), patched_label32) == 0 &&
|
||||
packet32[2] ==
|
||||
(0xc8010000u |
|
||||
(static_cast<uint32_t>(patched_address32 >> 32u) & 0xffffu)) &&
|
||||
packet32[3] == static_cast<uint32_t>(patched_address32) &&
|
||||
packet32[6] ==
|
||||
((static_cast<uint32_t>(patched_address32) & ~0x3u) | 0x2u) &&
|
||||
packet32[7] ==
|
||||
((static_cast<uint32_t>(patched_address32 >> 32u) & 0x3ffffu) |
|
||||
0xa5a40000u) &&
|
||||
packet32[8] == patched_label32 && execute(packet32.data(), 14),
|
||||
"32-bit native wait patch did not update metadata and hardware packet");
|
||||
|
||||
alignas(8) uint64_t label64 = 0x1122334455667788ull;
|
||||
std::array<uint32_t, 16> packet64{};
|
||||
AgcCommandBufferLayout dcb64{packet64.data(),
|
||||
packet64.data() + packet64.size(),
|
||||
packet64.data(),
|
||||
packet64.data() + packet64.size(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
0};
|
||||
const auto address64 = reinterpret_cast<uint64_t>(&label64);
|
||||
auto *emitted64 = Gen5::AgcDcbWaitRegMem(
|
||||
reinterpret_cast<Gen5::CommandBuffer *>(&dcb64), 1, 3, 0, 0,
|
||||
&label64, label64, UINT64_MAX, 400);
|
||||
Require(
|
||||
"AgcWaitPackets", "native 64-bit packet",
|
||||
Gen5::AgcDcbWaitOnAddressGetSize(1) == 64 &&
|
||||
Gen5::AgcDcbWaitOnAddressGetSize(2) == 0 &&
|
||||
emitted64 == packet64.data() &&
|
||||
dcb64.cursor_up == packet64.data() + packet64.size() &&
|
||||
packet64[0] == 0xc0027904u && packet64[1] == 0x342u &&
|
||||
packet64[2] ==
|
||||
(0xc8020000u |
|
||||
(static_cast<uint32_t>(address64 >> 32u) & 0xffffu)) &&
|
||||
packet64[3] == static_cast<uint32_t>(address64) &&
|
||||
packet64[4] == 0xc0079300u && packet64[5] == 0x13u &&
|
||||
packet64[6] == (static_cast<uint32_t>(address64) & ~0x7u) &&
|
||||
packet64[7] ==
|
||||
(static_cast<uint32_t>(address64 >> 32u) & 0x3ffffu) &&
|
||||
packet64[8] == static_cast<uint32_t>(label64) &&
|
||||
packet64[9] == static_cast<uint32_t>(label64 >> 32u) &&
|
||||
packet64[10] == UINT32_MAX && packet64[11] == UINT32_MAX &&
|
||||
packet64[12] == 25u && packet64[13] == 0xc0017904u &&
|
||||
packet64[14] == 0x342u && packet64[15] == 0xc8000000u &&
|
||||
execute(packet64.data(), packet64.size()),
|
||||
"64-bit waitOnAddress stream differs from native AGC");
|
||||
|
||||
alignas(8) uint64_t patched_label64 = 0x11223344aabbccddull;
|
||||
const auto patched_address64 = reinterpret_cast<uint64_t>(&patched_label64);
|
||||
packet64[6] |= 0x5u;
|
||||
packet64[7] |= 0x5a580000u;
|
||||
Require(
|
||||
"AgcWaitPackets", "native 64-bit patch",
|
||||
Gen5::AgcWaitRegMemPatchAddress(packet64.data(), &patched_label64) == 0 &&
|
||||
Gen5::AgcWaitRegMemPatchReference(packet64.data(),
|
||||
0xdeadbeefaabbccddull) == 0 &&
|
||||
packet64[2] ==
|
||||
(0xc8020000u |
|
||||
(static_cast<uint32_t>(patched_address64 >> 32u) & 0xffffu)) &&
|
||||
packet64[3] == static_cast<uint32_t>(patched_address64) &&
|
||||
packet64[6] ==
|
||||
((static_cast<uint32_t>(patched_address64) & ~0x7u) | 0x5u) &&
|
||||
packet64[7] ==
|
||||
((static_cast<uint32_t>(patched_address64 >> 32u) & 0x3ffffu) |
|
||||
0x5a580000u) &&
|
||||
packet64[8] == 0xaabbccddu && packet64[9] == 0x11223344u &&
|
||||
execute(packet64.data(), packet64.size()),
|
||||
"64-bit native wait patch did not preserve the native high reference DWORD");
|
||||
|
||||
std::array<uint32_t, 16> invalid{};
|
||||
const uint32_t short_payload = 0x342u;
|
||||
Require("AgcWaitPackets", "invalid packet",
|
||||
Gen5::AgcWaitRegMemPatchAddress(invalid.data(), &label32) ==
|
||||
packet_mismatch &&
|
||||
Gen5::AgcWaitRegMemPatchReference(invalid.data(), label32) ==
|
||||
packet_mismatch &&
|
||||
!Gen5::AgcIsWaitUserDataPacket(
|
||||
KYTY_PM4(2, Pm4::IT_SET_UCONFIG_REG, 1), &short_payload),
|
||||
"native wait patch accepted a packet without the AGC metadata prefix");
|
||||
std::printf("[host] %-32s ok\n", "AgcWaitPackets");
|
||||
}
|
||||
|
||||
void CheckPm4ContextStateOperations(RenderContext &renderer) {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer);
|
||||
constexpr auto primitive_type = static_cast<Prospero::PrimitiveType>(0x35u);
|
||||
struct AgcCommandBufferLayout {
|
||||
using Callback = KYTY_SYSV_ABI bool (*)(Gen5::CommandBuffer *, uint32_t,
|
||||
void *);
|
||||
|
||||
uint32_t *bottom;
|
||||
uint32_t *top;
|
||||
uint32_t *cursor_up;
|
||||
uint32_t *cursor_down;
|
||||
Callback callback;
|
||||
void *user_data;
|
||||
uint32_t reserved_dw;
|
||||
};
|
||||
static_assert(offsetof(AgcCommandBufferLayout, cursor_up) == 0x10);
|
||||
static_assert(offsetof(AgcCommandBufferLayout, reserved_dw) == 0x30);
|
||||
|
||||
HW::RenderControl original_control{};
|
||||
original_control.depth_clear_enable = true;
|
||||
@@ -22366,12 +22501,12 @@ void CheckPm4WaitResume(RenderContext &renderer) {
|
||||
child[2] = static_cast<uint32_t>(address(&child_observation));
|
||||
child[3] = static_cast<uint32_t>(address(&child_observation) >> 32u);
|
||||
child[4] = 0;
|
||||
child[5] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_MEM_32);
|
||||
child[6] = static_cast<uint32_t>(address(&label));
|
||||
child[7] = static_cast<uint32_t>(address(&label) >> 32u);
|
||||
child[8] = UINT32_MAX;
|
||||
child[5] = KYTY_PM4(7, Pm4::IT_WAIT_REG_MEM, 0);
|
||||
child[6] = 0x10u | 3u;
|
||||
child[7] = static_cast<uint32_t>(address(&label));
|
||||
child[8] = static_cast<uint32_t>(address(&label) >> 32u);
|
||||
child[9] = 1;
|
||||
child[10] = 0x10u | 3u;
|
||||
child[10] = UINT32_MAX;
|
||||
|
||||
std::array<uint32_t, 4> nested{};
|
||||
nested[0] = KYTY_PM4(4, Pm4::IT_INDIRECT_BUFFER, 0);
|
||||
@@ -22578,6 +22713,12 @@ int main(int argc, char **argv) {
|
||||
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--agc-wait-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
CheckAgcWaitPackets(vulkan.RuntimeRenderer());
|
||||
CheckPm4WaitResume(vulkan.RuntimeRenderer());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--rewind-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
CheckPm4RewindResume(vulkan.RuntimeRenderer());
|
||||
@@ -22741,6 +22882,7 @@ int main(int argc, char **argv) {
|
||||
CheckPm4DirectShaderRegisterFallback(vulkan.RuntimeRenderer());
|
||||
CheckPm4GuardBandRegisterRanges(vulkan.RuntimeRenderer());
|
||||
CheckPm4PolygonOffsetRegisters(vulkan.RuntimeRenderer());
|
||||
CheckAgcWaitPackets(vulkan.RuntimeRenderer());
|
||||
CheckPm4ContextStateOperations(vulkan.RuntimeRenderer());
|
||||
CheckPm4WaitResume(vulkan.RuntimeRenderer());
|
||||
CheckPm4RewindResume(vulkan.RuntimeRenderer());
|
||||
|
||||
Reference in New Issue
Block a user