mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-24 04:46:56 +02:00
gpu: remove the PS4-era constant engine, marker NOPs and EVENT_WRITE_EOP/EOS packets
This commit is contained in:
@@ -694,6 +694,8 @@ if(BUILD_TESTING)
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --gpu-command-lane-only)
|
||||
add_test(NAME wait_until_safe_for_rendering
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --wait-until-safe-for-rendering-only)
|
||||
add_test(NAME pm4_flip
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --flip-only)
|
||||
add_test(NAME depth_bits
|
||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --depth-bits-only)
|
||||
add_test(NAME msaa_storage
|
||||
|
||||
@@ -50,13 +50,6 @@ private:
|
||||
|
||||
class CommandProcessor {
|
||||
public:
|
||||
struct FlipInfo {
|
||||
int handle = 0;
|
||||
int index = 0;
|
||||
int flip_mode = 0;
|
||||
int64_t flip_arg = 0;
|
||||
};
|
||||
|
||||
CommandProcessor(RenderContext& renderer, int interrupt_event_id)
|
||||
: m_renderer(renderer), m_interrupt_event_id(interrupt_event_id) {}
|
||||
~CommandProcessor() = default;
|
||||
@@ -90,18 +83,13 @@ public:
|
||||
void DrawIndirectMulti(uint32_t data_offset, uint32_t max_count_or_count,
|
||||
const volatile uint32_t* count_addr, uint32_t stride_in_bytes,
|
||||
IndirectDrawRegisters registers, uint32_t draw_initiator, bool indexed);
|
||||
void WriteAtEndOfPipe32(uint32_t cache_policy, uint32_t event_write_dest,
|
||||
uint32_t eop_event_type, uint32_t cache_action, uint32_t event_index,
|
||||
void WriteAtEndOfPipe32(uint32_t eop_event_type, uint32_t cache_action, uint32_t event_index,
|
||||
uint32_t event_write_source, void* dst_gpu_addr, uint32_t value,
|
||||
uint32_t interrupt_selector, uint32_t interrupt_context_id = 0);
|
||||
void WriteAtEndOfPipe64(uint32_t cache_policy, uint32_t event_write_dest,
|
||||
uint32_t eop_event_type, uint32_t cache_action, uint32_t event_index,
|
||||
uint32_t interrupt_selector, uint32_t interrupt_context_id);
|
||||
void WriteAtEndOfPipe64(uint32_t eop_event_type, uint32_t cache_action, uint32_t event_index,
|
||||
uint32_t event_write_source, void* dst_gpu_addr, uint64_t value,
|
||||
uint32_t interrupt_selector, uint32_t interrupt_context_id = 0);
|
||||
void Flip();
|
||||
void Flip(void* dst_gpu_addr, uint32_t value);
|
||||
void FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache_action, void* dst_gpu_addr,
|
||||
uint32_t value);
|
||||
uint32_t interrupt_selector, uint32_t interrupt_context_id);
|
||||
void Flip(int handle, int index, int flip_mode, int64_t flip_arg);
|
||||
void PrepareCpuFlip(uint64_t request_id);
|
||||
void SynchronizeGpu();
|
||||
void TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id);
|
||||
@@ -111,19 +99,7 @@ public:
|
||||
void WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index);
|
||||
void TriggerEvent(uint32_t event_type, uint32_t event_index, uint64_t event_address = 0);
|
||||
|
||||
void SetUserDataMarker(HW::UserSgprType type) { m_user_data_marker = type; }
|
||||
[[nodiscard]] HW::UserSgprType GetUserDataMarker() const { return m_user_data_marker; }
|
||||
|
||||
void ResetDeCe();
|
||||
void SetCeComplete(bool complete) { m_ce_complete = complete; }
|
||||
void WaitCe();
|
||||
void WaitDeDiff(uint32_t diff);
|
||||
void WaitForRewind(bool valid);
|
||||
void IncrementDe();
|
||||
void IncrementCe();
|
||||
|
||||
void WriteConstRam(uint32_t offset, const uint32_t* src, uint32_t dw_num);
|
||||
void DumpConstRam(uint32_t* dst, uint32_t offset, uint32_t dw_num);
|
||||
|
||||
template <typename T>
|
||||
void WaitRegMem(uint32_t func, const T* addr, T ref, T mask, uint32_t poll, uint32_t wait_op);
|
||||
@@ -140,18 +116,15 @@ public:
|
||||
Pm4ProcessResult Process(Pm4Execution& execution, std::span<const uint32_t> commands);
|
||||
void ProcessIndirectBuffer(std::span<const uint32_t> commands, bool chain);
|
||||
|
||||
void SetFlip(const FlipInfo& flip) { m_flip = flip; }
|
||||
|
||||
[[nodiscard]] uint64_t GetSubmitId() const { return m_submit_id; }
|
||||
void SetSubmitId(uint64_t submit_id) { m_submit_id = submit_id; }
|
||||
[[nodiscard]] bool IsAsyncComputeQueue() const { return m_interrupt_event_id >= 0x20; }
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_write_dest, uint32_t eop_event_type,
|
||||
uint32_t cache_action, uint32_t event_index, uint32_t event_write_source,
|
||||
void* dst_gpu_addr, T value, uint32_t interrupt_selector,
|
||||
uint32_t interrupt_context_id);
|
||||
void WriteAtEndOfPipe(uint32_t eop_event_type, uint32_t cache_action, uint32_t event_index,
|
||||
uint32_t event_write_source, void* dst_gpu_addr, T value,
|
||||
uint32_t interrupt_selector, uint32_t interrupt_context_id);
|
||||
void ProcessPm4(Pm4Execution& execution);
|
||||
void SuspendPm4();
|
||||
uint32_t NumInstances();
|
||||
@@ -159,30 +132,22 @@ private:
|
||||
CommandScheduler& GetScheduler() const { return m_renderer.GetCommandScheduler(); }
|
||||
CommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
|
||||
|
||||
RenderContext& m_renderer;
|
||||
HW::Context m_ctx;
|
||||
HW::Context m_saved_ctx;
|
||||
bool m_context_state_pushed = false;
|
||||
HW::UserConfig m_ucfg;
|
||||
HW::Shader m_sh_ctx;
|
||||
HW::UserSgprType m_user_data_marker = HW::UserSgprType::Unknown;
|
||||
uint32_t m_index_type_and_size = 0;
|
||||
uint32_t m_index_buffer_size = 0;
|
||||
uint64_t m_index_base_addr = 0;
|
||||
uint64_t m_draw_indirect_args_base_addr = 0;
|
||||
uint64_t m_dispatch_indirect_args_base_addr = 0;
|
||||
RenderContext& m_renderer;
|
||||
HW::Context m_ctx;
|
||||
HW::Context m_saved_ctx;
|
||||
bool m_context_state_pushed = false;
|
||||
HW::UserConfig m_ucfg;
|
||||
HW::Shader m_sh_ctx;
|
||||
uint32_t m_index_type_and_size = 0;
|
||||
uint32_t m_index_buffer_size = 0;
|
||||
uint64_t m_index_base_addr = 0;
|
||||
uint64_t m_draw_indirect_args_base_addr = 0;
|
||||
uint64_t m_dispatch_indirect_args_base_addr = 0;
|
||||
// Persistent draw state. Indirect draws leave the address of their last instance count,
|
||||
// read only when a later draw inherits it.
|
||||
uint32_t m_num_instances = 1;
|
||||
uint64_t m_num_instances_addr = 0;
|
||||
|
||||
uint32_t m_de_count = 0;
|
||||
uint32_t m_ce_count = 0;
|
||||
bool m_ce_complete = false;
|
||||
|
||||
uint32_t m_const_ram[0x3000] = {0};
|
||||
|
||||
FlipInfo m_flip;
|
||||
const int m_interrupt_event_id;
|
||||
uint64_t m_submit_id = 0;
|
||||
uint64_t m_synthetic_occlusion_counter = 0;
|
||||
|
||||
@@ -199,8 +199,6 @@ constexpr auto MakeOpcodeDispatchTable() {
|
||||
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;
|
||||
g_cp_op_func[Pm4::IT_EVENT_WRITE_EOP] = CpOpEventWriteEop;
|
||||
g_cp_op_func[Pm4::IT_EVENT_WRITE_EOS] = CpOpEventWriteEos;
|
||||
g_cp_op_func[Pm4::IT_DMA_DATA] = CpOpDmaData;
|
||||
g_cp_op_func[Pm4::IT_ACQUIRE_MEM] = CpOpAcquireMem;
|
||||
g_cp_op_func[Pm4::IT_REWIND] = CpOpRewind;
|
||||
@@ -211,12 +209,6 @@ constexpr auto MakeOpcodeDispatchTable() {
|
||||
g_cp_op_func[Pm4::IT_SET_CONTEXT_REG_INDIRECT] = CpOpIndirectCxRegs;
|
||||
g_cp_op_func[Pm4::IT_SET_SH_REG_INDIRECT] = CpOpIndirectShRegs;
|
||||
g_cp_op_func[Pm4::IT_SET_UCONFIG_REG_INDIRECT] = CpOpIndirectUcRegs;
|
||||
g_cp_op_func[Pm4::IT_WRITE_CONST_RAM] = CpOpWriteConstRam;
|
||||
g_cp_op_func[Pm4::IT_DUMP_CONST_RAM] = CpOpDumpConstRam;
|
||||
g_cp_op_func[Pm4::IT_INCREMENT_CE_COUNTER] = CpOpIncrementCeCounter;
|
||||
g_cp_op_func[Pm4::IT_INCREMENT_DE_COUNTER] = CpOpIncrementDeCounter;
|
||||
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;
|
||||
|
||||
|
||||
@@ -133,8 +133,6 @@ uint32_t CpOpWriteData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, u
|
||||
uint32_t CpOpIndirectBuffer(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpCopyData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpEventWrite(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpEventWriteEop(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpEventWriteEos(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpDmaData(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpAcquireMem(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpSetContextReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
@@ -143,12 +141,6 @@ uint32_t CpOpSetUconfigReg(CommandProcessor&, uint32_t, const uint32_t*, uint32_
|
||||
uint32_t CpOpIndirectCxRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpIndirectShRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpIndirectUcRegs(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpWriteConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpDumpConstRam(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpIncrementCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpIncrementDeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpWaitOnCeCounter(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpWaitOnDeCounterDiff(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpGetLodStats(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpDispatchReset(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
uint32_t CpOpWaitRegMem32(CommandProcessor&, uint32_t, const uint32_t*, uint32_t, uint32_t);
|
||||
|
||||
@@ -1068,9 +1068,8 @@ KYTY_HW_SH_PARSER(HwShSetCsUserSgpr) {
|
||||
auto write_num = UserSgprWriteNum(slot, reg_num, 16u, "cs");
|
||||
|
||||
for (uint32_t i = 0; i < write_num; i++) {
|
||||
cp.GetShCtx().SetCsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker());
|
||||
cp.GetShCtx().SetCsUserSgpr(slot + i, buffer[i]);
|
||||
}
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
|
||||
return reg_num;
|
||||
}
|
||||
@@ -1085,9 +1084,8 @@ KYTY_HW_SH_PARSER(HwShSetPsUserSgpr) {
|
||||
auto write_num = UserSgprWriteNum(slot, reg_num, 32u, "ps");
|
||||
|
||||
for (uint32_t i = 0; i < write_num; i++) {
|
||||
cp.GetShCtx().SetPsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker());
|
||||
cp.GetShCtx().SetPsUserSgpr(slot + i, buffer[i]);
|
||||
}
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
|
||||
return reg_num;
|
||||
}
|
||||
@@ -1102,9 +1100,8 @@ KYTY_HW_SH_PARSER(HwShSetGsUserSgpr) {
|
||||
auto write_num = UserSgprWriteNum(slot, reg_num, 32u, "gs");
|
||||
|
||||
for (uint32_t i = 0; i < write_num; i++) {
|
||||
cp.GetShCtx().SetGsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker());
|
||||
cp.GetShCtx().SetGsUserSgpr(slot + i, buffer[i]);
|
||||
}
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
|
||||
return reg_num;
|
||||
}
|
||||
@@ -1119,9 +1116,8 @@ KYTY_HW_SH_PARSER(HwShSetHsUserSgpr) {
|
||||
auto write_num = UserSgprWriteNum(slot, reg_num, 32u, "hs");
|
||||
|
||||
for (uint32_t i = 0; i < write_num; i++) {
|
||||
cp.GetShCtx().SetHsUserSgpr(slot + i, buffer[i], cp.GetUserDataMarker());
|
||||
cp.GetShCtx().SetHsUserSgpr(slot + i, buffer[i]);
|
||||
}
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
|
||||
return reg_num;
|
||||
}
|
||||
@@ -1700,24 +1696,6 @@ KYTY_CP_OP_PARSER(CpOpContextState) {
|
||||
return packet_size_dw - 1u;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpDumpConstRam) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0038300);
|
||||
|
||||
auto offset = buffer[0];
|
||||
auto dw_num = buffer[1];
|
||||
auto* dst = reinterpret_cast<uint32_t*>(buffer[2] | (static_cast<uint64_t>(buffer[3]) << 32u));
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(dw_num >= 0x3000);
|
||||
EXIT_NOT_IMPLEMENTED(offset > 0xbffc);
|
||||
EXIT_NOT_IMPLEMENTED((offset & 0x3u) != 0);
|
||||
|
||||
cp.DumpConstRam(dst, offset, dw_num);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpEventWrite) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
@@ -1738,90 +1716,16 @@ KYTY_CP_OP_PARSER(CpOpEventWrite) {
|
||||
return packet_size_dw - 1u;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpEventWriteEop) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0044700);
|
||||
|
||||
uint32_t cache_policy = (buffer[0] >> 25u) & 0x3u;
|
||||
uint32_t event_write_dest = ((buffer[0] >> 23u) & 0x10u) | ((buffer[2] >> 16u) & 0x01u);
|
||||
uint32_t eop_event_type = (buffer[0]) & 0x3fu;
|
||||
uint32_t cache_action = (buffer[0] >> 12u) & 0x3fu;
|
||||
uint32_t event_index = (buffer[0] >> 8u) & 0x7u;
|
||||
uint32_t event_write_source = ((buffer[2] >> 29u) & 0x7u);
|
||||
uint32_t interrupt_selector = (buffer[2] >> 24u) & 0x7u;
|
||||
auto* dst_gpu_addr =
|
||||
reinterpret_cast<void*>(buffer[1] | (static_cast<uint64_t>(buffer[2] & 0xffffu) << 32u));
|
||||
uint64_t value = (buffer[3] | (static_cast<uint64_t>(buffer[4]) << 32u));
|
||||
|
||||
cp.WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
event_write_source, dst_gpu_addr, value, interrupt_selector);
|
||||
|
||||
return 5;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpEventWriteEos) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0034802);
|
||||
|
||||
uint32_t cache_policy = (buffer[0] >> 25u) & 0x3u;
|
||||
uint32_t event_write_dest = 0;
|
||||
uint32_t eop_event_type = (buffer[0]) & 0x3fu;
|
||||
uint32_t cache_action = (buffer[0] >> 12u) & 0x3fu;
|
||||
uint32_t event_index = (buffer[0] >> 8u) & 0x7u;
|
||||
uint32_t event_write_source = ((buffer[2] >> 29u) & 0x7u);
|
||||
uint32_t interrupt_selector = (buffer[2] >> 24u) & 0x7u;
|
||||
|
||||
auto* dst_gpu_addr =
|
||||
reinterpret_cast<void*>(buffer[1] | (static_cast<uint64_t>(buffer[2] & 0xffffu) << 32u));
|
||||
uint32_t value = buffer[3];
|
||||
|
||||
cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
event_write_source, dst_gpu_addr, value, interrupt_selector);
|
||||
|
||||
return 4;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpFlip) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xc004105c);
|
||||
|
||||
CommandProcessor::FlipInfo f;
|
||||
|
||||
f.handle = static_cast<int>(buffer[0]);
|
||||
f.index = static_cast<int>(buffer[1]);
|
||||
f.flip_mode = static_cast<int>(buffer[2]);
|
||||
f.flip_arg = static_cast<int64_t>(buffer[3] | (static_cast<uint64_t>(buffer[4]) << 32u));
|
||||
|
||||
cp.SetFlip(f);
|
||||
cp.Flip();
|
||||
cp.Flip(static_cast<int>(buffer[0]), static_cast<int>(buffer[1]), static_cast<int>(buffer[2]),
|
||||
static_cast<int64_t>(buffer[3] | (static_cast<uint64_t>(buffer[4]) << 32u)));
|
||||
return 5;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpIncrementCeCounter) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008400);
|
||||
EXIT_NOT_IMPLEMENTED(buffer[0] != 1);
|
||||
|
||||
cp.IncrementCe();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpIncrementDeCounter) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008500);
|
||||
EXIT_NOT_IMPLEMENTED(buffer[0] != 0);
|
||||
|
||||
cp.IncrementDe();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpIndexType) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
@@ -2103,50 +2007,12 @@ KYTY_CP_OP_PARSER(CpOpIndirectUcRegs) {
|
||||
return KYTY_PM4_LEN(cmd_id) - 1u;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpMarker) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
uint32_t len_dw = ((cmd_id >> 16u) & 0x3fffu);
|
||||
|
||||
switch (buffer[0]) {
|
||||
case 0x68750004: cp.SetUserDataMarker(HW::UserSgprType::Vsharp); break;
|
||||
case 0x6875000d: cp.SetUserDataMarker(HW::UserSgprType::Region); break;
|
||||
case 0x68750777: {
|
||||
cp.Flip();
|
||||
break;
|
||||
}
|
||||
case 0x68750778: {
|
||||
auto* addr =
|
||||
reinterpret_cast<void*>(buffer[1] | (static_cast<uint64_t>(buffer[2]) << 32u));
|
||||
uint32_t value = buffer[3];
|
||||
cp.Flip(addr, value);
|
||||
break;
|
||||
}
|
||||
case 0x68750781: {
|
||||
auto* addr =
|
||||
reinterpret_cast<void*>(buffer[1] | (static_cast<uint64_t>(buffer[2]) << 32u));
|
||||
uint32_t value = buffer[3];
|
||||
uint32_t eop_event_type = buffer[4];
|
||||
uint32_t cache_action = buffer[5];
|
||||
cp.FlipWithInterrupt(eop_event_type, cache_action, addr, value);
|
||||
break;
|
||||
}
|
||||
// NOP payloads are caller-owned data; only complete known marker tags execute.
|
||||
default: break;
|
||||
}
|
||||
|
||||
return len_dw + 1;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpNop) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
auto r = KYTY_PM4_R(cmd_id);
|
||||
|
||||
if (r == Pm4::R_ZERO) {
|
||||
if ((buffer[0] & 0xffff0000u) == 0x68750000u) {
|
||||
return CpOpMarker(cp, cmd_id, buffer, dw, num_dw);
|
||||
}
|
||||
return KYTY_PM4_LEN(cmd_id) - 1;
|
||||
}
|
||||
|
||||
@@ -2204,12 +2070,10 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xc0061060);
|
||||
|
||||
uint32_t cache_policy = (buffer[0] >> 25u) & 0x3u;
|
||||
uint32_t eop_event_type = buffer[0] & 0x3fu;
|
||||
uint32_t event_index = (buffer[0] >> 8u) & 0x7u;
|
||||
uint32_t gcr_cntl = (buffer[0] >> 12u) & 0xfffu;
|
||||
uint32_t release_dst = (buffer[1] >> 16u) & 0x3u;
|
||||
uint32_t event_write_dest = 0;
|
||||
uint32_t data_sel = (buffer[1] >> 29u) & 0x7u;
|
||||
uint32_t interrupt_selector = (buffer[1] >> 24u) & 0x7u;
|
||||
auto* dst_gpu_addr =
|
||||
@@ -2250,16 +2114,15 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
|
||||
}
|
||||
|
||||
auto cache_action = ReleaseMemCacheActionFromGcr(gcr_cntl);
|
||||
cache_policy = 0;
|
||||
|
||||
if (data_sel == 1) {
|
||||
eop_event_type = 0x2f;
|
||||
event_index = 6;
|
||||
auto event_source = 2u;
|
||||
|
||||
cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action,
|
||||
event_index, event_source, dst_gpu_addr, static_cast<uint32_t>(value),
|
||||
interrupt_selector, interrupt_context_id);
|
||||
cp.WriteAtEndOfPipe32(eop_event_type, cache_action, event_index, event_source, dst_gpu_addr,
|
||||
static_cast<uint32_t>(value), interrupt_selector,
|
||||
interrupt_context_id);
|
||||
if (interrupt_selector == 0x01 || interrupt_selector == 0x02) {
|
||||
cp.BufferFlush();
|
||||
}
|
||||
@@ -2276,9 +2139,9 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
|
||||
event_index = 6;
|
||||
auto event_source = 1u;
|
||||
|
||||
cp.WriteAtEndOfPipe32(cache_policy, event_write_dest, eop_event_type, cache_action,
|
||||
event_index, event_source, dst_gpu_addr, static_cast<uint32_t>(value),
|
||||
interrupt_selector, interrupt_context_id);
|
||||
cp.WriteAtEndOfPipe32(eop_event_type, cache_action, event_index, event_source, dst_gpu_addr,
|
||||
static_cast<uint32_t>(value), interrupt_selector,
|
||||
interrupt_context_id);
|
||||
if (interrupt_selector == 0x01) {
|
||||
cp.BufferFlush();
|
||||
}
|
||||
@@ -2302,8 +2165,8 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
|
||||
data_sel = 4;
|
||||
}
|
||||
|
||||
cp.WriteAtEndOfPipe64(cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
data_sel, dst_gpu_addr, value, interrupt_selector, interrupt_context_id);
|
||||
cp.WriteAtEndOfPipe64(eop_event_type, cache_action, event_index, data_sel, dst_gpu_addr, value,
|
||||
interrupt_selector, interrupt_context_id);
|
||||
|
||||
return 7;
|
||||
}
|
||||
@@ -2524,42 +2387,6 @@ KYTY_CP_OP_PARSER(CpOpWaitRegMem64) {
|
||||
return CpOpWaitRegMemSized<uint64_t>(cp, cmd_id, buffer);
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpWaitOnCeCounter) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008600);
|
||||
EXIT_NOT_IMPLEMENTED(buffer[0] != 1);
|
||||
|
||||
cp.WaitCe();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpWaitOnDeCounterDiff) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008800);
|
||||
|
||||
cp.WaitDeDiff(buffer[0]);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpWriteConstRam) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
auto dw_num = (cmd_id >> 16u) & 0x3fffu;
|
||||
auto offset = buffer[0];
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(dw_num >= 0x3000);
|
||||
EXIT_NOT_IMPLEMENTED(offset > 0xbffc);
|
||||
EXIT_NOT_IMPLEMENTED((offset & 0x3u) != 0);
|
||||
|
||||
cp.WriteConstRam(offset, buffer + 1, dw_num);
|
||||
|
||||
return 1 + dw_num;
|
||||
}
|
||||
|
||||
KYTY_CP_OP_PARSER(CpOpWriteData) {
|
||||
KYTY_PROFILER_FUNCTION();
|
||||
|
||||
@@ -3519,9 +3346,7 @@ void GraphicsInitJmpTablesShIndirect() {
|
||||
|
||||
for (uint32_t slot = 0; slot < 16; slot++) {
|
||||
g_hw_sh_indirect_func[Pm4::COMPUTE_USER_DATA_0 + slot] = [](KYTY_HW_SH_INDIRECT_ARGS) {
|
||||
auto sgpr = cmd_offset - Pm4::COMPUTE_USER_DATA_0;
|
||||
cp.GetShCtx().SetCsUserSgpr(sgpr, value, cp.GetUserDataMarker());
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
cp.GetShCtx().SetCsUserSgpr(cmd_offset - Pm4::COMPUTE_USER_DATA_0, value);
|
||||
};
|
||||
}
|
||||
for (uint32_t slot = 0; slot < 4; slot++) {
|
||||
@@ -3532,21 +3357,15 @@ void GraphicsInitJmpTablesShIndirect() {
|
||||
for (uint32_t slot = 0; slot < 32; slot++) {
|
||||
g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_PS_0 + slot] =
|
||||
[](KYTY_HW_SH_INDIRECT_ARGS) {
|
||||
auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_PS_0;
|
||||
cp.GetShCtx().SetPsUserSgpr(sgpr, value, cp.GetUserDataMarker());
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
cp.GetShCtx().SetPsUserSgpr(cmd_offset - Pm4::SPI_SHADER_USER_DATA_PS_0, value);
|
||||
};
|
||||
g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_GS_0 + slot] =
|
||||
[](KYTY_HW_SH_INDIRECT_ARGS) {
|
||||
auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_GS_0;
|
||||
cp.GetShCtx().SetGsUserSgpr(sgpr, value, cp.GetUserDataMarker());
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
cp.GetShCtx().SetGsUserSgpr(cmd_offset - Pm4::SPI_SHADER_USER_DATA_GS_0, value);
|
||||
};
|
||||
g_hw_sh_indirect_func[Pm4::SPI_SHADER_USER_DATA_HS_0 + slot] =
|
||||
[](KYTY_HW_SH_INDIRECT_ARGS) {
|
||||
auto sgpr = cmd_offset - Pm4::SPI_SHADER_USER_DATA_HS_0;
|
||||
cp.GetShCtx().SetHsUserSgpr(sgpr, value, cp.GetUserDataMarker());
|
||||
cp.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
cp.GetShCtx().SetHsUserSgpr(cmd_offset - Pm4::SPI_SHADER_USER_DATA_HS_0, value);
|
||||
};
|
||||
}
|
||||
for (uint32_t slot = 0; slot < 4; slot++) {
|
||||
|
||||
@@ -127,16 +127,14 @@ void GuestGpu::SendCommandSync(Common::UniqueFunction<void>&& command) {
|
||||
done.acquire();
|
||||
}
|
||||
|
||||
void GuestGpu::Submit(std::span<const uint32_t> draw_commands,
|
||||
std::span<const uint32_t> constant_commands) {
|
||||
if (draw_commands.empty()) {
|
||||
void GuestGpu::Submit(std::span<const uint32_t> commands) {
|
||||
if (commands.empty()) {
|
||||
return;
|
||||
}
|
||||
Submission submission;
|
||||
submission.type = SubmissionType::Graphics;
|
||||
submission.queue_id = 0;
|
||||
submission.commands = draw_commands;
|
||||
submission.constant_commands = constant_commands;
|
||||
submission.type = SubmissionType::Graphics;
|
||||
submission.queue_id = 0;
|
||||
submission.commands = commands;
|
||||
Enqueue(std::move(submission));
|
||||
}
|
||||
|
||||
@@ -200,11 +198,8 @@ void CommandProcessor::Reset() {
|
||||
m_num_instances = 1;
|
||||
m_num_instances_addr = 0;
|
||||
m_predicate_skip = false;
|
||||
m_user_data_marker = HW::UserSgprType::Unknown;
|
||||
m_draw_indirect_args_base_addr = 0;
|
||||
m_dispatch_indirect_args_base_addr = 0;
|
||||
|
||||
std::memset(m_const_ram, 0, sizeof(m_const_ram));
|
||||
}
|
||||
|
||||
void CommandProcessor::ApplyContextStateOperation(ContextStateOperation operation) {
|
||||
@@ -246,47 +241,12 @@ void CommandProcessor::BufferWait() {
|
||||
GetScheduler().Finish();
|
||||
}
|
||||
|
||||
void CommandProcessor::ResetDeCe() {
|
||||
m_de_count = 0;
|
||||
m_ce_count = 0;
|
||||
m_ce_complete = false;
|
||||
}
|
||||
|
||||
void CommandProcessor::WaitCe() {
|
||||
if (m_ce_count <= m_de_count && !m_ce_complete) {
|
||||
SuspendPm4();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::WaitDeDiff(uint32_t diff) {
|
||||
EXIT_IF(m_de_count > m_ce_count);
|
||||
if (m_ce_count - m_de_count >= diff) {
|
||||
SuspendPm4();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::WaitForRewind(bool valid) {
|
||||
if (!valid) {
|
||||
SuspendPm4();
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::IncrementDe() {
|
||||
m_de_count++;
|
||||
}
|
||||
|
||||
void CommandProcessor::IncrementCe() {
|
||||
m_ce_count++;
|
||||
}
|
||||
|
||||
void CommandProcessor::WriteConstRam(uint32_t offset, const uint32_t* src, uint32_t dw_num) {
|
||||
memcpy(m_const_ram + offset / 4, src, static_cast<size_t>(dw_num) * 4);
|
||||
}
|
||||
|
||||
void CommandProcessor::DumpConstRam(uint32_t* dst, uint32_t offset, uint32_t dw_num) {
|
||||
memcpy(dst, m_const_ram + offset / 4, static_cast<size_t>(dw_num) * 4);
|
||||
}
|
||||
|
||||
bool TestWaitRegMemValue(uint64_t value, uint64_t ref, uint64_t mask, uint32_t func) {
|
||||
switch (func) {
|
||||
case 0: return true;
|
||||
@@ -541,64 +501,34 @@ bool GuestGpu::Process(Submission& submission) {
|
||||
if (first_slice) {
|
||||
submission.started = true;
|
||||
cp.SetSubmitId(++m_submit_id);
|
||||
cp.ResetDeCe();
|
||||
cp.SetFlip({});
|
||||
}
|
||||
|
||||
cp.BufferInit();
|
||||
bool complete = true;
|
||||
|
||||
switch (submission.type) {
|
||||
case SubmissionType::Graphics: {
|
||||
bool progressed = false;
|
||||
submission.constant_complete |= submission.constant_commands.empty();
|
||||
for (;;) {
|
||||
bool round_progress = false;
|
||||
if (!submission.constant_complete) {
|
||||
submission.constant_complete =
|
||||
cp.Process(submission.constant_execution, submission.constant_commands) ==
|
||||
Pm4ProcessResult::Complete;
|
||||
round_progress |= submission.constant_execution.MadeProgress();
|
||||
}
|
||||
cp.SetCeComplete(submission.constant_complete);
|
||||
if (!submission.command_complete) {
|
||||
submission.command_complete =
|
||||
cp.Process(submission.command_execution, submission.commands) ==
|
||||
Pm4ProcessResult::Complete;
|
||||
round_progress |= submission.command_execution.MadeProgress();
|
||||
}
|
||||
progressed |= round_progress;
|
||||
complete = submission.command_complete && submission.constant_complete;
|
||||
if (complete || !round_progress) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (progressed) {
|
||||
cp.BufferFlush();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SubmissionType::Compute: {
|
||||
const auto num_dw = static_cast<uint32_t>(submission.commands.size());
|
||||
const auto* buffer = submission.commands.data();
|
||||
static uint32_t compute_batch_log_count = 0;
|
||||
if (first_slice && num_dw <= 128 && compute_batch_log_count++ < 32) {
|
||||
LOGF("compute direct batch: data=0x%016" PRIx64 ", num_dw=%" PRIu32 "\n",
|
||||
reinterpret_cast<uint64_t>(buffer), num_dw);
|
||||
for (uint32_t i = 0; i < std::min<uint32_t>(num_dw, 16); i++) {
|
||||
LOGF("\t compute[%02" PRIu32 "] = 0x%08" PRIx32 "\n", i, buffer[i]);
|
||||
}
|
||||
}
|
||||
case SubmissionType::Compute:
|
||||
if (first_slice) {
|
||||
const auto num_dw = static_cast<uint32_t>(submission.commands.size());
|
||||
const auto* buffer = submission.commands.data();
|
||||
static uint32_t compute_batch_log_count = 0;
|
||||
if (num_dw <= 128 && compute_batch_log_count++ < 32) {
|
||||
LOGF("compute direct batch: data=0x%016" PRIx64 ", num_dw=%" PRIu32 "\n",
|
||||
reinterpret_cast<uint64_t>(buffer), num_dw);
|
||||
for (uint32_t i = 0; i < std::min<uint32_t>(num_dw, 16); i++) {
|
||||
LOGF("\t compute[%02" PRIu32 "] = 0x%08" PRIx32 "\n", i, buffer[i]);
|
||||
}
|
||||
}
|
||||
GraphicsDbgDumpDcb("cc", num_dw, buffer);
|
||||
}
|
||||
complete = cp.Process(submission.command_execution, submission.commands) ==
|
||||
Pm4ProcessResult::Complete;
|
||||
if (submission.command_execution.MadeProgress()) {
|
||||
[[fallthrough]];
|
||||
case SubmissionType::Graphics:
|
||||
complete =
|
||||
cp.Process(submission.execution, submission.commands) == Pm4ProcessResult::Complete;
|
||||
if (submission.execution.MadeProgress()) {
|
||||
cp.BufferFlush();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SubmissionType::FlipPreparation:
|
||||
cp.PrepareCpuFlip(submission.flip_request_id);
|
||||
break;
|
||||
@@ -1019,8 +949,7 @@ void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_write_dest,
|
||||
uint32_t eop_event_type, uint32_t cache_action,
|
||||
void CommandProcessor::WriteAtEndOfPipe(uint32_t eop_event_type, uint32_t cache_action,
|
||||
uint32_t event_index, uint32_t event_write_source,
|
||||
void* dst_gpu_addr, T value, uint32_t interrupt_selector,
|
||||
uint32_t interrupt_context_id) {
|
||||
@@ -1033,8 +962,6 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
const auto log_width = static_cast<int>(sizeof(T) * 2u);
|
||||
|
||||
LOGF("CommandProcessor::WriteAtEndOfPipe%u()\n"
|
||||
"\t cache_policy = 0x%08" PRIx32 "\n"
|
||||
"\t event_write_dest = 0x%08" PRIx32 "\n"
|
||||
"\t eop_event_type = 0x%08" PRIx32 "\n"
|
||||
"\t cache_action = 0x%08" PRIx32 "\n"
|
||||
"\t event_index = 0x%08" PRIx32 "\n"
|
||||
@@ -1043,13 +970,11 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
"\t interrupt_context = 0x%08" PRIx32 "\n"
|
||||
"\t dst_gpu_addr = 0x%016" PRIx64 "\n"
|
||||
"\t value = 0x%0*" PRIx64 "\n",
|
||||
bits, cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
event_write_source, interrupt_selector, interrupt_context_id,
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr), log_width, static_cast<uint64_t>(value));
|
||||
bits, eop_event_type, cache_action, event_index, event_write_source,
|
||||
interrupt_selector, interrupt_context_id, reinterpret_cast<uint64_t>(dst_gpu_addr),
|
||||
log_width, static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(cache_policy != 0x00000000);
|
||||
EXIT_NOT_IMPLEMENTED(event_write_dest != 0x00000000);
|
||||
// Dumped occlusion counters are written before any end-of-pipe signal reaches the guest.
|
||||
m_renderer.GetOcclusionQueries().Publish();
|
||||
|
||||
@@ -1093,9 +1018,6 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else if (eop_event_type == 0x04 && cache_action == 0x00 && event_index == 0x05) {
|
||||
write32();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 0x02:
|
||||
@@ -1156,9 +1078,7 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
case 0x04:
|
||||
case 0x14:
|
||||
case 0x28:
|
||||
if (((eop_event_type == 0x04 || eop_event_type == 0x28) &&
|
||||
event_index == 0x05) ||
|
||||
(event_index == 0x00)) {
|
||||
if (event_index == 0x00) {
|
||||
write64();
|
||||
return;
|
||||
}
|
||||
@@ -1179,12 +1099,6 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
default: break;
|
||||
}
|
||||
break;
|
||||
case 0x3b:
|
||||
if (eop_event_type == 0x04 && event_index == 0x05 && with_interrupt) {
|
||||
write64();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@@ -1195,26 +1109,22 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
|
||||
EXIT("unknown event type\n");
|
||||
}
|
||||
|
||||
void CommandProcessor::WriteAtEndOfPipe32(uint32_t cache_policy, uint32_t event_write_dest,
|
||||
uint32_t eop_event_type, uint32_t cache_action,
|
||||
void CommandProcessor::WriteAtEndOfPipe32(uint32_t eop_event_type, uint32_t cache_action,
|
||||
uint32_t event_index, uint32_t event_write_source,
|
||||
void* dst_gpu_addr, uint32_t value,
|
||||
uint32_t interrupt_selector,
|
||||
uint32_t interrupt_context_id) {
|
||||
WriteAtEndOfPipe(cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
event_write_source, dst_gpu_addr, value, interrupt_selector,
|
||||
interrupt_context_id);
|
||||
WriteAtEndOfPipe(eop_event_type, cache_action, event_index, event_write_source, dst_gpu_addr,
|
||||
value, interrupt_selector, interrupt_context_id);
|
||||
}
|
||||
|
||||
void CommandProcessor::WriteAtEndOfPipe64(uint32_t cache_policy, uint32_t event_write_dest,
|
||||
uint32_t eop_event_type, uint32_t cache_action,
|
||||
void CommandProcessor::WriteAtEndOfPipe64(uint32_t eop_event_type, uint32_t cache_action,
|
||||
uint32_t event_index, uint32_t event_write_source,
|
||||
void* dst_gpu_addr, uint64_t value,
|
||||
uint32_t interrupt_selector,
|
||||
uint32_t interrupt_context_id) {
|
||||
WriteAtEndOfPipe(cache_policy, event_write_dest, eop_event_type, cache_action, event_index,
|
||||
event_write_source, dst_gpu_addr, value, interrupt_selector,
|
||||
interrupt_context_id);
|
||||
WriteAtEndOfPipe(eop_event_type, cache_action, event_index, event_write_source, dst_gpu_addr,
|
||||
value, interrupt_selector, interrupt_context_id);
|
||||
}
|
||||
|
||||
void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id) {
|
||||
@@ -1304,65 +1214,20 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index,
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::Flip() {
|
||||
void CommandProcessor::Flip(int handle, int index, int flip_mode, int64_t flip_arg) {
|
||||
if (GraphicsRunDebugDumpEnabled()) {
|
||||
LOGF("CommandProcessor::Flip()\n");
|
||||
}
|
||||
m_renderer.GetOcclusionQueries().Publish();
|
||||
|
||||
auto& command = CurrentBuffer();
|
||||
auto request = Sync::PrepareVideoOutFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode,
|
||||
m_flip.flip_arg);
|
||||
auto request = Sync::PrepareVideoOutFlip(command, handle, index, flip_mode, flip_arg);
|
||||
(void)command.Handle();
|
||||
GetScheduler().DeferPriorityOperation(
|
||||
[&renderer = m_renderer, request] { renderer.GetVideoOut().CompleteFlip(request); });
|
||||
GetScheduler().Flush();
|
||||
}
|
||||
|
||||
void CommandProcessor::Flip(void* dst_gpu_addr, uint32_t value) {
|
||||
if (GraphicsRunDebugDumpEnabled()) {
|
||||
LOGF("CommandProcessor::Flip()\n"
|
||||
"\t dst_gpu_addr = 0x%016" PRIx64 "\n"
|
||||
"\t value = 0x%08" PRIx32 "\n",
|
||||
reinterpret_cast<uint64_t>(dst_gpu_addr), value);
|
||||
}
|
||||
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
m_renderer.GetOcclusionQueries().Publish();
|
||||
std::memcpy(dst_gpu_addr, &value, sizeof(value));
|
||||
Flip();
|
||||
}
|
||||
|
||||
void CommandProcessor::FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache_action,
|
||||
void* dst_gpu_addr, uint32_t value) {
|
||||
auto& command = CurrentBuffer();
|
||||
|
||||
if (GraphicsRunDebugDumpEnabled()) {
|
||||
LOGF("CommandProcessor::FlipWithInterrupt()\n"
|
||||
"\t eop_event_type = 0x%08" PRIx32 "\n"
|
||||
"\t cache_action = 0x%08" PRIx32 "\n"
|
||||
"\t dst_gpu_addr = 0x%016" PRIx64 "\n"
|
||||
"\t value = 0x%08" PRIx32 "\n",
|
||||
eop_event_type, cache_action, reinterpret_cast<uint64_t>(dst_gpu_addr), value);
|
||||
}
|
||||
|
||||
if (eop_event_type != 0x00000004 || cache_action != 0x00000038) {
|
||||
EXIT("unknown event type\n");
|
||||
}
|
||||
EXIT_IF(dst_gpu_addr == nullptr);
|
||||
m_renderer.GetOcclusionQueries().Publish();
|
||||
std::memcpy(dst_gpu_addr, &value, sizeof(value));
|
||||
auto request = Sync::PrepareVideoOutFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode,
|
||||
m_flip.flip_arg);
|
||||
(void)command.Handle();
|
||||
GetScheduler().DeferPriorityOperation(
|
||||
[&renderer = m_renderer, event_id = m_interrupt_event_id, request] {
|
||||
renderer.GetVideoOut().CompleteFlip(request);
|
||||
renderer.TriggerInterrupt(event_id, 0);
|
||||
});
|
||||
GetScheduler().Flush();
|
||||
}
|
||||
|
||||
void CommandProcessor::PrepareCpuFlip(uint64_t request_id) {
|
||||
auto& command = CurrentBuffer();
|
||||
if (g_current_processor != nullptr) {
|
||||
|
||||
@@ -35,8 +35,7 @@ public:
|
||||
void Wake();
|
||||
|
||||
// Submitted command memory is borrowed and must remain valid until GPU execution completes.
|
||||
void Submit(std::span<const uint32_t> draw_commands,
|
||||
std::span<const uint32_t> constant_commands);
|
||||
void Submit(std::span<const uint32_t> commands);
|
||||
void SubmitCompute(uint32_t queue, std::span<const uint32_t> commands);
|
||||
void SubmitFlipPreparation(uint64_t request_id);
|
||||
// Insert an ordered graphics drain; only a previous suspend point can block the caller.
|
||||
@@ -60,14 +59,10 @@ private:
|
||||
SubmissionType type = SubmissionType::Graphics;
|
||||
uint32_t queue_id = 0;
|
||||
std::span<const uint32_t> commands;
|
||||
std::span<const uint32_t> constant_commands;
|
||||
Pm4Execution command_execution;
|
||||
Pm4Execution constant_execution;
|
||||
bool started = false;
|
||||
bool command_complete = false;
|
||||
bool constant_complete = false;
|
||||
bool blocked = false;
|
||||
uint64_t flip_request_id = 0;
|
||||
Pm4Execution execution;
|
||||
bool started = false;
|
||||
bool blocked = false;
|
||||
uint64_t flip_request_id = 0;
|
||||
};
|
||||
|
||||
void Enqueue(Submission submission);
|
||||
|
||||
@@ -597,14 +597,10 @@ struct ShaderRegisters {
|
||||
}
|
||||
};
|
||||
|
||||
enum class UserSgprType { Unknown, Region, Vsharp };
|
||||
|
||||
struct UserSgprInfo {
|
||||
static constexpr int SGPRS_MAX = 32;
|
||||
|
||||
uint32_t value[SGPRS_MAX] = {0};
|
||||
UserSgprType type[SGPRS_MAX] = {};
|
||||
uint32_t count = 0;
|
||||
uint32_t value[SGPRS_MAX] = {0};
|
||||
};
|
||||
|
||||
struct VertexShaderInfo {
|
||||
@@ -1056,30 +1052,10 @@ public:
|
||||
void SetCsShader(const CsStageRegisters& cs_regs) { m_cs.cs_regs = cs_regs; }
|
||||
void SetCsWaveSize(uint8_t wave_size) { m_cs.cs_regs.wave_size = wave_size; }
|
||||
|
||||
void SetPsUserSgpr(uint32_t id, uint32_t value, UserSgprType type) {
|
||||
m_ps.ps_user_sgpr.value[id] = value;
|
||||
m_ps.ps_user_sgpr.type[id] = type;
|
||||
m_ps.ps_user_sgpr.count =
|
||||
((id + 1) > m_ps.ps_user_sgpr.count ? (id + 1) : m_ps.ps_user_sgpr.count);
|
||||
}
|
||||
void SetCsUserSgpr(uint32_t id, uint32_t value, UserSgprType type) {
|
||||
m_cs.cs_user_sgpr.value[id] = value;
|
||||
m_cs.cs_user_sgpr.type[id] = type;
|
||||
m_cs.cs_user_sgpr.count =
|
||||
((id + 1) > m_cs.cs_user_sgpr.count ? (id + 1) : m_cs.cs_user_sgpr.count);
|
||||
}
|
||||
void SetHsUserSgpr(uint32_t id, uint32_t value, UserSgprType type) {
|
||||
m_vs.hs_user_sgpr.value[id] = value;
|
||||
m_vs.hs_user_sgpr.type[id] = type;
|
||||
m_vs.hs_user_sgpr.count =
|
||||
((id + 1) > m_vs.hs_user_sgpr.count ? (id + 1) : m_vs.hs_user_sgpr.count);
|
||||
}
|
||||
void SetGsUserSgpr(uint32_t id, uint32_t value, UserSgprType type) {
|
||||
m_vs.gs_user_sgpr.value[id] = value;
|
||||
m_vs.gs_user_sgpr.type[id] = type;
|
||||
m_vs.gs_user_sgpr.count =
|
||||
((id + 1) > m_vs.gs_user_sgpr.count ? (id + 1) : m_vs.gs_user_sgpr.count);
|
||||
}
|
||||
void SetPsUserSgpr(uint32_t id, uint32_t value) { m_ps.ps_user_sgpr.value[id] = value; }
|
||||
void SetCsUserSgpr(uint32_t id, uint32_t value) { m_cs.cs_user_sgpr.value[id] = value; }
|
||||
void SetHsUserSgpr(uint32_t id, uint32_t value) { m_vs.hs_user_sgpr.value[id] = value; }
|
||||
void SetGsUserSgpr(uint32_t id, uint32_t value) { m_vs.gs_user_sgpr.value[id] = value; }
|
||||
|
||||
[[nodiscard]] const PixelShaderInfo& GetPs() const { return m_ps; }
|
||||
[[nodiscard]] const VertexShaderInfo& GetVs() const { return m_vs; }
|
||||
|
||||
@@ -54,7 +54,6 @@ constexpr auto MakeOpcodeNames() {
|
||||
names[IT_DRAW_INDIRECT_MULTI] = "IT_DRAW_INDIRECT_MULTI";
|
||||
names[IT_DRAW_INDEX_AUTO] = "IT_DRAW_INDEX_AUTO";
|
||||
names[IT_NUM_INSTANCES] = "IT_NUM_INSTANCES";
|
||||
names[IT_INDIRECT_BUFFER_CNST] = "IT_INDIRECT_BUFFER_CNST";
|
||||
names[IT_DRAW_INDEX_OFFSET_2] = "IT_DRAW_INDEX_OFFSET_2";
|
||||
names[IT_WRITE_DATA] = "IT_WRITE_DATA";
|
||||
names[IT_MEM_SEMAPHORE] = "IT_MEM_SEMAPHORE";
|
||||
@@ -66,8 +65,6 @@ constexpr auto MakeOpcodeNames() {
|
||||
names[IT_PFP_SYNC_ME] = "IT_PFP_SYNC_ME";
|
||||
names[IT_SURFACE_SYNC] = "IT_SURFACE_SYNC";
|
||||
names[IT_EVENT_WRITE] = "IT_EVENT_WRITE";
|
||||
names[IT_EVENT_WRITE_EOP] = "IT_EVENT_WRITE_EOP";
|
||||
names[IT_EVENT_WRITE_EOS] = "IT_EVENT_WRITE_EOS";
|
||||
names[IT_RELEASE_MEM] = "IT_RELEASE_MEM";
|
||||
names[IT_DMA_DATA] = "IT_DMA_DATA";
|
||||
names[IT_ACQUIRE_MEM] = "IT_ACQUIRE_MEM";
|
||||
@@ -80,12 +77,6 @@ constexpr auto MakeOpcodeNames() {
|
||||
names[IT_SET_QUEUE_REG] = "IT_SET_QUEUE_REG";
|
||||
names[IT_SET_UCONFIG_REG] = "IT_SET_UCONFIG_REG";
|
||||
names[IT_SET_UCONFIG_REG_INDEX] = "IT_SET_UCONFIG_REG_INDEX";
|
||||
names[IT_WRITE_CONST_RAM] = "IT_WRITE_CONST_RAM";
|
||||
names[IT_DUMP_CONST_RAM] = "IT_DUMP_CONST_RAM";
|
||||
names[IT_INCREMENT_CE_COUNTER] = "IT_INCREMENT_CE_COUNTER";
|
||||
names[IT_INCREMENT_DE_COUNTER] = "IT_INCREMENT_DE_COUNTER";
|
||||
names[IT_WAIT_ON_CE_COUNTER] = "IT_WAIT_ON_CE_COUNTER";
|
||||
names[IT_WAIT_ON_DE_COUNTER_DIFF] = "IT_WAIT_ON_DE_COUNTER_DIFF";
|
||||
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";
|
||||
|
||||
@@ -40,7 +40,6 @@ constexpr uint32_t IT_INDEX_TYPE = 0x2A;
|
||||
constexpr uint32_t IT_DRAW_INDIRECT_MULTI = 0x2C;
|
||||
constexpr uint32_t IT_DRAW_INDEX_AUTO = 0x2D;
|
||||
constexpr uint32_t IT_NUM_INSTANCES = 0x2F;
|
||||
constexpr uint32_t IT_INDIRECT_BUFFER_CNST = 0x33;
|
||||
constexpr uint32_t IT_DRAW_INDEX_OFFSET_2 = 0x35;
|
||||
constexpr uint32_t IT_WRITE_DATA = 0x37;
|
||||
constexpr uint32_t IT_MEM_SEMAPHORE = 0x39;
|
||||
@@ -53,8 +52,6 @@ constexpr uint32_t IT_CP_DMA = 0x41;
|
||||
constexpr uint32_t IT_PFP_SYNC_ME = 0x42;
|
||||
constexpr uint32_t IT_SURFACE_SYNC = 0x43;
|
||||
constexpr uint32_t IT_EVENT_WRITE = 0x46;
|
||||
constexpr uint32_t IT_EVENT_WRITE_EOP = 0x47;
|
||||
constexpr uint32_t IT_EVENT_WRITE_EOS = 0x48;
|
||||
constexpr uint32_t IT_RELEASE_MEM = 0x49;
|
||||
constexpr uint32_t IT_DMA_DATA = 0x50;
|
||||
constexpr uint32_t IT_ACQUIRE_MEM = 0x58;
|
||||
@@ -67,12 +64,6 @@ constexpr uint32_t IT_SET_SH_REG = 0x76;
|
||||
constexpr uint32_t IT_SET_QUEUE_REG = 0x78;
|
||||
constexpr uint32_t IT_SET_UCONFIG_REG = 0x79;
|
||||
constexpr uint32_t IT_SET_UCONFIG_REG_INDEX = 0x7A;
|
||||
constexpr uint32_t IT_WRITE_CONST_RAM = 0x81;
|
||||
constexpr uint32_t IT_DUMP_CONST_RAM = 0x83;
|
||||
constexpr uint32_t IT_INCREMENT_CE_COUNTER = 0x84;
|
||||
constexpr uint32_t IT_INCREMENT_DE_COUNTER = 0x85;
|
||||
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;
|
||||
|
||||
+1
-10
@@ -3510,13 +3510,7 @@ int KYTY_SYSV_ABI AgcSetPacketPredication(uint32_t* packet, uint32_t predication
|
||||
int KYTY_SYSV_ABI AgcSetNop(uint32_t* packet) {
|
||||
PRINT_NAME();
|
||||
|
||||
const auto size = AgcGetPacketSize(packet);
|
||||
|
||||
packet[0] = (packet[0] & 0xffff0003u) | (Pm4::IT_NOP << 8u);
|
||||
// Prevent the disabled payload from being treated as an executable marker.
|
||||
if (size > 1 && (packet[1] & 0xffff0000u) == 0x68750000u) {
|
||||
packet[1] &= 0xffffu;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -3793,9 +3787,6 @@ int KYTY_SYSV_ABI AgcQueueEndOfPipeActionPatchAddress(uint32_t* cmd,
|
||||
op == Pm4::IT_RELEASE_MEM) {
|
||||
cmd[3] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
||||
cmd[4] = static_cast<uint32_t>((vaddr >> 32u) & 0xffffffffu);
|
||||
} else if (op == Pm4::IT_EVENT_WRITE_EOP) {
|
||||
cmd[2] = static_cast<uint32_t>(vaddr & 0xffffffffu);
|
||||
cmd[3] = (cmd[3] & 0xffff0000u) | static_cast<uint32_t>((vaddr >> 32u) & 0xffffu);
|
||||
} else {
|
||||
EXIT("unsupported queueEndOfPipeAction packet for address patch: 0x%08" PRIx32 "\n",
|
||||
cmd[0]);
|
||||
@@ -4115,7 +4106,7 @@ static TessellationDriverState g_tessellation_driver_state {};
|
||||
static void submit_dcb(uint32_t* dcb, uint32_t size_in_dwords) {
|
||||
GraphicsDbgDumpDcb("d", size_in_dwords, dcb);
|
||||
EXIT_IF(g_renderer == nullptr);
|
||||
g_renderer->GetGpu().Submit(std::span {dcb, size_in_dwords}, {});
|
||||
g_renderer->GetGpu().Submit(std::span {dcb, size_in_dwords});
|
||||
}
|
||||
|
||||
int KYTY_SYSV_ABI AgcDriverSubmitDcb(const Packet* packet) {
|
||||
|
||||
@@ -2712,7 +2712,7 @@ public:
|
||||
write(compute_list.data(), &async_value, 29);
|
||||
// A frame can contain many lists; completing them must not age either cache.
|
||||
for (uint32_t i = 0; i < 32; ++i) {
|
||||
gpu.Submit(graphics_list, {});
|
||||
gpu.Submit(graphics_list);
|
||||
gpu.SubmitCompute(0x20, compute_list);
|
||||
}
|
||||
finish();
|
||||
@@ -2832,7 +2832,7 @@ public:
|
||||
release_lane.acquire();
|
||||
});
|
||||
lane_entered.acquire();
|
||||
gpu.Submit(before, {});
|
||||
gpu.Submit(before);
|
||||
std::binary_semaphore queued_returned{0};
|
||||
std::jthread queued([&] {
|
||||
gpu.SuspendPoint();
|
||||
@@ -2849,7 +2849,7 @@ public:
|
||||
"suspend-point insertion drained pending guest graphics");
|
||||
}
|
||||
queued.join();
|
||||
gpu.Submit(after, {});
|
||||
gpu.Submit(after);
|
||||
release_lane.release();
|
||||
bool prefix_reached = false;
|
||||
bool graphics_ordered = false;
|
||||
@@ -3000,8 +3000,7 @@ public:
|
||||
auto packet = make_release_mem(0, 0, nullptr, 0);
|
||||
Pm4Execution execution;
|
||||
const auto result = processor->Process(execution, packet);
|
||||
processor->IncrementDe();
|
||||
const bool cache_and_counter_did_not_submit =
|
||||
const bool cache_event_did_not_submit =
|
||||
result == Pm4ProcessResult::Complete &&
|
||||
gpu_scheduler.CurrentTick() == tick_before;
|
||||
|
||||
@@ -3039,7 +3038,7 @@ public:
|
||||
const auto interrupt_result =
|
||||
processor->Process(gds_interrupt_execution, gds_interrupt_only);
|
||||
parser_kept_nonblocking_boundaries =
|
||||
cache_and_counter_did_not_submit &&
|
||||
cache_event_did_not_submit &&
|
||||
cb_db_release_did_not_submit &&
|
||||
interrupt_result == Pm4ProcessResult::Complete &&
|
||||
gpu_scheduler.CurrentTick() == interrupt_tick + 1 &&
|
||||
@@ -3067,9 +3066,8 @@ public:
|
||||
"CPU-only unmap submitted or waited for unrelated native work");
|
||||
Require("GpuCommandLane", "nonblocking GPU packets",
|
||||
parser_did_not_wait_gpu && parser_kept_nonblocking_boundaries,
|
||||
"a cache event, GL2 writeback, DE counter, or interrupt boundary "
|
||||
"used the wrong "
|
||||
"submission behavior");
|
||||
"a cache event, GL2 writeback, or interrupt boundary used the "
|
||||
"wrong submission behavior");
|
||||
|
||||
alignas(uint64_t) uint64_t release_label = 0;
|
||||
alignas(uint64_t) uint64_t gds_label = UINT64_MAX;
|
||||
@@ -3078,10 +3076,13 @@ public:
|
||||
processor->BufferInit();
|
||||
|
||||
const auto clock_before = Sync::ReadReferenceClock();
|
||||
processor->WriteAtEndOfPipe64(0, 0, 0x04, 0x38, 5, 4,
|
||||
&release_label, UINT64_MAX, 2);
|
||||
Require("GpuCommandLane", "EOP reference clock with interrupt",
|
||||
release_label >= clock_before &&
|
||||
auto clock_release =
|
||||
make_release_mem(3, 2, &release_label, UINT64_MAX, 0x04u);
|
||||
Pm4Execution clock_execution;
|
||||
Require("GpuCommandLane", "release reference clock with interrupt",
|
||||
processor->Process(clock_execution, clock_release) ==
|
||||
Pm4ProcessResult::Complete &&
|
||||
release_label >= clock_before &&
|
||||
release_label <= Sync::ReadReferenceClock(),
|
||||
"clock write with writeback and interrupt lost its data");
|
||||
|
||||
@@ -3163,7 +3164,7 @@ public:
|
||||
graphics_gate_entered.release();
|
||||
graphics_gate_release.acquire();
|
||||
});
|
||||
gpu.Submit(live_graphics_commands, {});
|
||||
gpu.Submit(live_graphics_commands);
|
||||
graphics_gate_entered.acquire();
|
||||
live_graphics_commands[4] = 22;
|
||||
graphics_gate_release.release();
|
||||
@@ -3240,7 +3241,7 @@ public:
|
||||
std::array<uint32_t, 5> no_interrupt_graphics_commands{};
|
||||
write_packet(no_interrupt_graphics_commands.data(),
|
||||
&no_interrupt_graphics_value, 55);
|
||||
gpu.Submit(no_interrupt_graphics_commands, {});
|
||||
gpu.Submit(no_interrupt_graphics_commands);
|
||||
gpu.WaitForIdle();
|
||||
finish_gpu();
|
||||
|
||||
@@ -3280,7 +3281,7 @@ public:
|
||||
uint32_t graphics_interrupt_label = 0xa5a5a5a5u;
|
||||
auto graphics_interrupt_commands = make_interrupt_packet(
|
||||
1, 1, &graphics_interrupt_label, 0x11223344u, 0);
|
||||
gpu.Submit(graphics_interrupt_commands, {});
|
||||
gpu.Submit(graphics_interrupt_commands);
|
||||
gpu.WaitForIdle();
|
||||
finish_gpu();
|
||||
|
||||
@@ -3396,7 +3397,7 @@ public:
|
||||
stream_gate_entered.release();
|
||||
stream_gate_release.acquire();
|
||||
});
|
||||
gpu.Submit(polling_commands, {});
|
||||
gpu.Submit(polling_commands);
|
||||
stream_gate_entered.acquire();
|
||||
stream_gate_release.release();
|
||||
uint32_t packet_marker_a_at_callback = UINT32_MAX;
|
||||
@@ -3447,7 +3448,7 @@ public:
|
||||
commands[14] = static_cast<uint32_t>(address(&suffix));
|
||||
commands[15] = static_cast<uint32_t>(address(&suffix) >> 32u);
|
||||
commands[16] = 22;
|
||||
gpu.Submit(commands, {});
|
||||
gpu.Submit(commands);
|
||||
|
||||
std::binary_semaphore ordered_started{0};
|
||||
std::atomic<bool> ordered_finished{false};
|
||||
@@ -3477,7 +3478,7 @@ public:
|
||||
label = 0;
|
||||
prefix = 0;
|
||||
suffix = 0;
|
||||
gpu.Submit(commands, {});
|
||||
gpu.Submit(commands);
|
||||
|
||||
std::binary_semaphore unmap_complete{0};
|
||||
std::jthread unmap_thread([&] {
|
||||
@@ -3618,7 +3619,7 @@ public:
|
||||
Require("GpuCommandLane", "DMA_DATA packet assembly",
|
||||
dma_cursor == dma_commands.size(),
|
||||
"DMA_DATA packet stream has the wrong size");
|
||||
gpu.Submit(dma_commands, {});
|
||||
gpu.Submit(dma_commands);
|
||||
gpu.WaitForIdle();
|
||||
constexpr uint32_t clean_fill_value = 0xdecafbad;
|
||||
gpu.SendCommandSync([&] {
|
||||
@@ -10907,8 +10908,8 @@ public:
|
||||
return base + (wave_size == 64 ? 0x8000u : 0u) + 0x100u + phase * 0x2000u;
|
||||
};
|
||||
for (u32 sgpr = 0; sgpr < 16; ++sgpr)
|
||||
shaders.SetCsUserSgpr(sgpr, 0, HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(8, 0x92u, HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(sgpr, 0);
|
||||
shaders.SetCsUserSgpr(8, 0x92u);
|
||||
for (u32 phase = 0; phase < 3; ++phase) {
|
||||
const auto &code = phase == 1 ? writer : reader;
|
||||
shaders.SetCsShader({.data_addr = reinterpret_cast<uint64_t>(code.data()),
|
||||
@@ -10920,7 +10921,7 @@ public:
|
||||
output.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
shaders.SetCsUserSgpr(12 + i, output.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12 + i, output.fields[i]);
|
||||
ShaderComputeInputInfo input{};
|
||||
(void)context.GetPipelineCache().GetComputeProgram(
|
||||
shaders.GetCs(), processor.GetCtx().GetShaderRegisters(), input);
|
||||
@@ -11012,7 +11013,7 @@ public:
|
||||
out.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
shaders.SetCsUserSgpr(i, out.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, out.fields[i]);
|
||||
uint64_t original_id = 0;
|
||||
struct Case { uint64_t address; u32 value; bool update; u32 field = 0; };
|
||||
for (const auto test : {Case{first, 41, false}, Case{first, 41, false},
|
||||
@@ -11123,7 +11124,7 @@ public:
|
||||
}
|
||||
user_data[6] = active_lanes;
|
||||
for (u32 i = 0; i < user_data.size(); ++i)
|
||||
shaders.SetCsUserSgpr(i, user_data[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, user_data[i]);
|
||||
Require(name, "reset caller output", context.InvalidateMemory(output, wave_size * 4),
|
||||
"caller output escaped mapped memory");
|
||||
std::array<float, 64> actual{};
|
||||
@@ -11270,8 +11271,8 @@ public:
|
||||
out.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u) | (3u << 28u);
|
||||
for (u32 i = 0; i < 4; ++i) {
|
||||
shaders.SetCsUserSgpr(i, input.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i + 4, out.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, input.fields[i]);
|
||||
shaders.SetCsUserSgpr(i + 4, out.fields[i]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, wave == 32 ? 0x8041u : 0x41u);
|
||||
cache.ReadMemory(output, wave * sizeof(u32));
|
||||
@@ -11381,11 +11382,9 @@ public:
|
||||
DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||
for (u32 i = 0; i < 4; ++i)
|
||||
shaders.SetCsUserSgpr(i, output.fields[i],
|
||||
HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, output.fields[i]);
|
||||
for (u32 i = 0; i < 3; ++i)
|
||||
shaders.SetCsUserSgpr(4 + i, i == 2 ? count : groups[i],
|
||||
HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(4 + i, i == 2 ? count : groups[i]);
|
||||
processor.DispatchDirect(groups[0], groups[1], groups[2],
|
||||
wave_size == 32 ? 0x8049u : 0x49u);
|
||||
cache.CopyBuffer(base + 63 * sizeof(u32), 0, sizeof(u32), false,
|
||||
@@ -11542,8 +11541,7 @@ public:
|
||||
descriptor.fields[3] = DstSel(4, 5, 6, 7) |
|
||||
(static_cast<u32>(Prospero::BufferFormat::k32UInt) << 12u);
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
shaders.SetCsUserSgpr(sgpr + i, descriptor.fields[i],
|
||||
HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(sgpr + i, descriptor.fields[i]);
|
||||
}
|
||||
};
|
||||
for (size_t index = 0; index < cases.size(); index++) {
|
||||
@@ -11561,7 +11559,7 @@ public:
|
||||
.wave_size = 64, .user_sgpr = 15});
|
||||
for (u32 i = 0; i < 3; i++) {
|
||||
set_buffer(i * 4u, args + i * 4u, 4);
|
||||
shaders.SetCsUserSgpr(12u + i, test.dimensions[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12u + i, test.dimensions[i]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
}
|
||||
@@ -11640,8 +11638,7 @@ public:
|
||||
.wave_size = 64, .user_sgpr = 15});
|
||||
for (u32 i = 0; i < 3; i++) {
|
||||
set_buffer(i * 4u, count_args + i * 4u, 4);
|
||||
shaders.SetCsUserSgpr(12u + i, i == 0 ? count : 1u,
|
||||
HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12u + i, i == 0 ? count : 1u);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
Require(name, "GPU-owned descriptor count", cache.HasGpuDirtyBytes(count_args, 4),
|
||||
@@ -11730,8 +11727,8 @@ public:
|
||||
.num_thread_x = 1, .num_thread_y = 1, .num_thread_z = 1,
|
||||
.wave_size = 64, .user_sgpr = 2, .tgid_x_en = true,
|
||||
.tgid_y_en = true, .tgid_z_en = true});
|
||||
shaders.SetCsUserSgpr(0, static_cast<u32>(parameters), HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(1, static_cast<u32>(parameters >> 32u), HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(0, static_cast<u32>(parameters));
|
||||
shaders.SetCsUserSgpr(1, static_cast<u32>(parameters >> 32u));
|
||||
const ShaderBufferResource table_buffer{{static_cast<u32>(table_address),
|
||||
static_cast<u32>(table_address >> 32u) | (148u << 16u), 2, 0x5204u}};
|
||||
LibKernel::Memory::WriteBacking(parameters, table_buffer.fields, sizeof(table_buffer.fields));
|
||||
@@ -11860,7 +11857,7 @@ public:
|
||||
.wave_size = 64, .user_sgpr = 15});
|
||||
for (u32 word = 0; word < 3u; ++word) {
|
||||
set_buffer(word * 4u, address + word * stride, 4u);
|
||||
shaders.SetCsUserSgpr(12u + word, values[word], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12u + word, values[word]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
};
|
||||
@@ -11900,9 +11897,9 @@ public:
|
||||
.user_sgpr = 13, .tgid_x_en = true});
|
||||
set_buffer(0, record_keys, based ? 5u : 3u, based ? 8u : 12u);
|
||||
set_buffer(4, record_table, 2u, 192u);
|
||||
if (based) shaders.SetCsUserSgpr(5, record_table >> 32u, HW::UserSgprType::Unknown);
|
||||
if (based) shaders.SetCsUserSgpr(5, record_table >> 32u);
|
||||
set_buffer(8, record_output, wave * 2u, 8u);
|
||||
shaders.SetCsUserSgpr(12, std::countr_zero(wave), HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12, std::countr_zero(wave));
|
||||
processor.DispatchIndirect(record_args, 0x41u |
|
||||
(wave == 32u ? 1u << Pm4::COMPUTE_DISPATCH_INITIATOR_CS_W32_EN_SHIFT : 0u));
|
||||
cache.ReadMemory(record_output, expected_output.size() * 4u);
|
||||
@@ -12086,7 +12083,7 @@ public:
|
||||
.wave_size = 64, .user_sgpr = 15});
|
||||
for (u32 axis = 0; axis < 3; axis++) {
|
||||
set_buffer(axis * 4, lds_args + axis * sizeof(u32), sizeof(u32));
|
||||
shaders.SetCsUserSgpr(12 + axis, groups[axis], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(12 + axis, groups[axis]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
Require(name, "GPU-authored LDS dispatch arguments",
|
||||
@@ -12421,7 +12418,7 @@ public:
|
||||
static_cast<uint32_t>(dcc_address >> 32u) | (4u << 16u),
|
||||
count, 0x00014004u, fill_case.fill, 0, 0x200, 0, count, 1};
|
||||
for (uint32_t i = 0; i < (goat ? 4u : user_data.size()); i++) {
|
||||
shaders.SetCsUserSgpr(i, user_data[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, user_data[i]);
|
||||
}
|
||||
executor.DispatchDirect(0, scheduler.Current(), (count + 63) / 64, 1, 1, 0x41u, false);
|
||||
};
|
||||
@@ -12856,8 +12853,8 @@ public:
|
||||
.num_thread_x = 2, .num_thread_y = 2, .num_thread_z = 1,
|
||||
.wave_size = 64, .user_sgpr = 16, .tidig_comp_cnt = 1});
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
shaders.SetCsUserSgpr(i, target.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(8u + i, depth_bits.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, target.fields[i]);
|
||||
shaders.SetCsUserSgpr(8u + i, depth_bits.fields[i]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
|
||||
@@ -12955,8 +12952,8 @@ public:
|
||||
const std::array<u32, 8> args{std::bit_cast<u32>(1.0f), 0, 0, std::bit_cast<u32>(1.0f),
|
||||
1, 1, 2, (2u << 16u) | 4u};
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
shaders.SetCsUserSgpr(i, target.fields[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(8u + i, args[i], HW::UserSgprType::Unknown);
|
||||
shaders.SetCsUserSgpr(i, target.fields[i]);
|
||||
shaders.SetCsUserSgpr(8u + i, args[i]);
|
||||
}
|
||||
processor.DispatchDirect(1, 1, 1, 0x41u);
|
||||
for (const int row : {1, 2, 3}) {
|
||||
@@ -19149,8 +19146,8 @@ public:
|
||||
shaders.SetEsShaderBase(indirect_vs);
|
||||
shaders.SetPsShaderBase(pixel_address);
|
||||
shaders.SetGsShaderResource2({.user_sgpr = 2});
|
||||
shaders.SetGsUserSgpr(0, 7, HW::UserSgprType::Unknown);
|
||||
shaders.SetGsUserSgpr(1, 5, HW::UserSgprType::Unknown);
|
||||
shaders.SetGsUserSgpr(0, 7);
|
||||
shaders.SetGsUserSgpr(1, 5);
|
||||
user_config.SetPrimitiveType(Prospero::PrimitiveType::kTriList);
|
||||
for (const bool indexed : {false, true}) {
|
||||
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
|
||||
@@ -19237,8 +19234,7 @@ public:
|
||||
reinterpret_cast<uint64_t>(&attribute)};
|
||||
shaders.SetGsShaderResource2({.user_sgpr = 4});
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
shaders.SetGsUserSgpr(i, static_cast<u32>(tables[i / 2] >> (i % 2 * 32)),
|
||||
HW::UserSgprType::Unknown);
|
||||
shaders.SetGsUserSgpr(i, static_cast<u32>(tables[i / 2] >> (i % 2 * 32)));
|
||||
}
|
||||
const auto check = [&](const char *step, uint64_t vertex_shader, bool indexed, u32 first) {
|
||||
shaders.SetEsShaderBase(vertex_shader);
|
||||
@@ -19306,7 +19302,7 @@ public:
|
||||
shaders.SetPsShaderBase(rect_ps);
|
||||
shaders.SetGsShaderResource2({.user_sgpr = 4});
|
||||
for (u32 i = 0; i < 4; i++) {
|
||||
shaders.SetGsUserSgpr(i, rect_buffer.fields[i], HW::UserSgprType::Vsharp);
|
||||
shaders.SetGsUserSgpr(i, rect_buffer.fields[i]);
|
||||
}
|
||||
registers.SetPsInControl(0x8001);
|
||||
registers.SetPsInputEna(2);
|
||||
@@ -48474,6 +48470,12 @@ void CheckPm4NativeTargetGeometryRegisters(RenderContext &renderer) {
|
||||
legacy_slots_are_unhandled &= g_hw_sh_func[offset] == nullptr &&
|
||||
g_hw_sh_indirect_func[offset] == nullptr;
|
||||
}
|
||||
// PS5 has no constant engine: WRITE_CONST_RAM, DUMP_CONST_RAM, the CE/DE
|
||||
// counter increments and waits. RELEASE_MEM replaces EVENT_WRITE_EOP/EOS.
|
||||
for (const uint32_t opcode :
|
||||
{0x47u, 0x48u, 0x81u, 0x83u, 0x84u, 0x85u, 0x86u, 0x88u}) {
|
||||
legacy_slots_are_unhandled &= g_cp_op_func[opcode] == nullptr;
|
||||
}
|
||||
// Restoring shader state after Toolkit rendering still emits the compiler's
|
||||
// GS-front allocation metadata at 0xca.
|
||||
for (uint32_t offset = 0x0cbu; offset <= 0x0ebu; offset++) {
|
||||
@@ -48507,7 +48509,8 @@ void CheckPm4NativeTargetGeometryRegisters(RenderContext &renderer) {
|
||||
Require("Pm4NativeTargetGeometry", "legacy register holes",
|
||||
legacy_slots_are_unhandled && native_pace_slots_are_handled &&
|
||||
native_ps_address_slots_are_handled && native_index_size_packet_complete,
|
||||
"a removed GCN register has a handler or a native packet is not handled");
|
||||
"a removed GCN register or PS4 packet has a handler or a native packet is "
|
||||
"not handled");
|
||||
std::printf("[host] %-32s ok\n", "Pm4NativeTargetGeometry");
|
||||
}
|
||||
|
||||
@@ -49283,8 +49286,8 @@ void CheckPm4DrawIndirectMultiPacket(RenderContext &renderer) {
|
||||
"indirect draw did not write the expected user SGPR offsets");
|
||||
};
|
||||
// These locations match the captured NGG prolog: user SGPR9/10 become s17/s18.
|
||||
shaders.SetGsUserSgpr(9, 17821, HW::UserSgprType::Unknown);
|
||||
shaders.SetGsUserSgpr(10, 0x898f3f24u, HW::UserSgprType::Unknown);
|
||||
shaders.SetGsUserSgpr(9, 17821);
|
||||
shaders.SetGsUserSgpr(10, 0x898f3f24u);
|
||||
arguments = {0, 1};
|
||||
std::array<uint32_t, 5> indexed_packet{
|
||||
KYTY_PM4(5, Pm4::IT_DRAW_INDEX_INDIRECT, 0), 0,
|
||||
@@ -49595,25 +49598,18 @@ void CheckPm4IndirectControlFlow(RenderContext &renderer) {
|
||||
Gen5::AgcCbNop(reinterpret_cast<Gen5::CommandBuffer*>(&payload_dcb), 3) == payload.data() &&
|
||||
payload == std::array<uint32_t, 3>{0xc0011000u, 0x12345678u, 0x9abcdef0u},
|
||||
"NOP emitter overwrote the caller's reserved payload");
|
||||
for (const uint32_t value : {0x68750820u, 0x68751777u, 0x68751004u}) {
|
||||
// The PS4-era flip tags are payload too.
|
||||
for (const uint32_t value : {0x68750820u, 0x68751777u, 0x68751004u,
|
||||
0x68750777u, 0x68750778u, 0x68750781u}) {
|
||||
std::array<uint32_t, 8> commands{KYTY_PM4(3, Pm4::IT_NOP, Pm4::R_ZERO), value, 0x12345678u};
|
||||
std::copy(completion.begin(), completion.end(), commands.begin() + 3);
|
||||
processor.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
selected = 0;
|
||||
Pm4Execution execution;
|
||||
Require(name, "opaque NOP payload",
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Complete && selected == 7 &&
|
||||
processor.GetUserDataMarker() == HW::UserSgprType::Unknown && commands[1] == value,
|
||||
"a NOP payload prefix executed a marker or blocked the following packet");
|
||||
commands[1] == value,
|
||||
"a NOP payload executed or blocked the following packet");
|
||||
}
|
||||
const std::array<uint32_t, 2> vsharp_marker{
|
||||
KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_ZERO), 0x68750004u};
|
||||
Pm4Execution marker_execution;
|
||||
Require(name, "exact user-data marker",
|
||||
processor.Process(marker_execution, vsharp_marker) == Pm4ProcessResult::Complete &&
|
||||
processor.GetUserDataMarker() == HW::UserSgprType::Vsharp,
|
||||
"exact marker dispatch lost the existing user-data annotation");
|
||||
processor.SetUserDataMarker(HW::UserSgprType::Unknown);
|
||||
alignas(8) uint64_t released = 0;
|
||||
std::array<uint32_t, 20> disabled_commands{};
|
||||
const auto disabled_write = write(&returned, 99);
|
||||
@@ -49634,7 +49630,7 @@ void CheckPm4IndirectControlFlow(RenderContext &renderer) {
|
||||
Gen5::AgcSetNop(disabled_commands.data() + 5) == 0 && Gen5::AgcSetNop(release) == 0 &&
|
||||
disabled_commands[0] == ((disabled_write[0] & 0xffff00ffu) | (Pm4::IT_NOP << 8u)) &&
|
||||
disabled_commands[5] == KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_ZERO) &&
|
||||
disabled_commands[6] == 0x123u &&
|
||||
disabled_commands[6] == 0x68750123u &&
|
||||
release[0] == KYTY_PM4(8, Pm4::IT_NOP, Pm4::R_ZERO) &&
|
||||
unpatched_commands[7] == KYTY_PM4(8, Pm4::IT_NOP, Pm4::R_RELEASE_MEM) &&
|
||||
Gen5::AgcGetPacketSize(disabled_commands.data()) == disabled_write.size() &&
|
||||
@@ -49644,7 +49640,7 @@ void CheckPm4IndirectControlFlow(RenderContext &renderer) {
|
||||
unpatched_commands.begin() + 1) &&
|
||||
std::equal(disabled_commands.begin() + 8, disabled_commands.end(),
|
||||
unpatched_commands.begin() + 8),
|
||||
"SetNop changed a packet length, kept its operation or marker, or touched its payload");
|
||||
"SetNop changed a packet length, kept its operation, or touched its payload");
|
||||
selected = returned = 0;
|
||||
Pm4Execution disabled_execution;
|
||||
Require(name, "SetNop execution",
|
||||
@@ -49801,7 +49797,7 @@ void CheckWaitUntilSafeForRendering() {
|
||||
hold[3] = static_cast<uint32_t>(address(&gate) >> 32u);
|
||||
hold[4] = 1;
|
||||
hold[5] = UINT32_MAX;
|
||||
gpu.Submit(hold, {});
|
||||
gpu.Submit(hold);
|
||||
Require(name, "flip black",
|
||||
VideoOut::VideoOutSubmitFlip(handle, index_black, flip_mode_vsync, 0) == 0,
|
||||
"CPU flip failed");
|
||||
@@ -49847,6 +49843,92 @@ void CheckWaitUntilSafeForRendering() {
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
// R_FLIP itself publishes the dumped occlusion counters, then flips.
|
||||
void CheckPm4Flip() {
|
||||
namespace EventQueue = LibKernel::EventQueue;
|
||||
constexpr const char *name = "Pm4Flip";
|
||||
Config::Load({.printf_direction = Config::LogDirection::Silent,
|
||||
.occlusion_queries_enabled = true});
|
||||
Require(name, "video", SDL_InitSubSystem(SDL_INIT_VIDEO),
|
||||
"SDL video init failed");
|
||||
WindowContext window;
|
||||
window.graphic_ctx.screen_width = 64;
|
||||
window.graphic_ctx.screen_height = 64;
|
||||
window.window =
|
||||
SDL_CreateWindow(name, 64, 64, SDL_WINDOW_VULKAN | SDL_WINDOW_HIDDEN);
|
||||
Require(name, "window", window.window != nullptr,
|
||||
"hidden Vulkan window failed");
|
||||
window.CreateVulkan();
|
||||
auto &video_out = VideoOut::VideoOutInit(64, 64, *window.presenter);
|
||||
auto &renderer = *window.render_context;
|
||||
renderer.InitializeGpu(&video_out);
|
||||
auto &gpu = renderer.GetGpu();
|
||||
Require(name, "occlusion queries", renderer.GetOcclusionQueries().Enabled(),
|
||||
"the device has no host occlusion queries");
|
||||
|
||||
const int handle = VideoOut::VideoOutOpen(255, 0, 0, nullptr);
|
||||
EventQueue::KernelEqueue flips = EventQueue::KERNEL_EQUEUE_INVALID;
|
||||
uint32_t udata = 0;
|
||||
Require(name, "events",
|
||||
handle > 0 && EventQueue::KernelCreateEqueue(&flips, "flips") == 0 &&
|
||||
VideoOut::VideoOutAddFlipEvent(flips, handle, &udata) == 0,
|
||||
"video-out or flip event registration failed");
|
||||
GraphicsInitJmpTables();
|
||||
|
||||
alignas(16) std::array<uint64_t, OCCLUSION_QUERY_DBS * 2> results{};
|
||||
constexpr int64_t flip_arg = 0x777;
|
||||
std::array<uint32_t, 14> commands{};
|
||||
const auto dump = [&](size_t at, const uint64_t *counter) {
|
||||
const auto address = reinterpret_cast<uint64_t>(counter);
|
||||
commands[at] = KYTY_PM4(4, Pm4::IT_EVENT_WRITE, Pm4::R_ZERO);
|
||||
commands[at + 1] = 0x139u;
|
||||
commands[at + 2] = static_cast<uint32_t>(address);
|
||||
commands[at + 3] = static_cast<uint32_t>(address >> 32u);
|
||||
};
|
||||
// Begin and end z-pass dumps, then a vsync flip of the blank buffer.
|
||||
dump(0, &results[0]);
|
||||
dump(4, &results[1]);
|
||||
commands[8] = KYTY_PM4(6, Pm4::IT_NOP, Pm4::R_FLIP);
|
||||
commands[9] = static_cast<uint32_t>(handle);
|
||||
commands[10] = static_cast<uint32_t>(-1);
|
||||
commands[11] = 1;
|
||||
commands[12] = flip_arg;
|
||||
bool complete = false;
|
||||
bool published = true;
|
||||
gpu.SendCommandSync([&] {
|
||||
CommandProcessor processor(renderer, 0);
|
||||
processor.BufferInit();
|
||||
Pm4Execution execution;
|
||||
complete =
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Complete;
|
||||
for (const auto counter : results) {
|
||||
published &= (counter & OCCLUSION_QUERY_READY) != 0;
|
||||
}
|
||||
processor.BufferFlush();
|
||||
});
|
||||
|
||||
EventQueue::KernelEvent event{};
|
||||
int count = 0;
|
||||
LibKernel::KernelUseconds timeout = 2'000'000;
|
||||
int64_t flipped_arg = -1;
|
||||
Require(name, "flip",
|
||||
complete && published &&
|
||||
EventQueue::KernelWaitEqueue(flips, &event, 1, &count,
|
||||
&timeout) == 0 &&
|
||||
count == 1 &&
|
||||
VideoOut::VideoOutGetEventData(&event, &flipped_arg) == 0 &&
|
||||
flipped_arg == flip_arg,
|
||||
"R_FLIP did not publish the occlusion counters or flip");
|
||||
|
||||
gpu.WaitForIdle();
|
||||
Require(name, "close", VideoOut::VideoOutClose(handle) == 0,
|
||||
"video-out close failed");
|
||||
EventQueue::KernelDeleteEqueue(flips);
|
||||
renderer.ShutdownGpu();
|
||||
VideoOut::VideoOutShutdown();
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckPm4WaitResume(RenderContext &renderer) {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer, 0);
|
||||
@@ -50008,58 +50090,6 @@ void CheckPm4RewindResume(RenderContext &renderer) {
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
void CheckPm4CeCompletion(RenderContext &renderer) {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor(renderer, 0);
|
||||
uint32_t suffix = 0;
|
||||
const auto address = reinterpret_cast<uint64_t>(&suffix);
|
||||
|
||||
std::array<uint32_t, 9> commands{};
|
||||
commands[0] = 0xc0008600u;
|
||||
commands[1] = 1;
|
||||
commands[2] = 0xc0008500u;
|
||||
commands[3] = 0;
|
||||
commands[4] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[5] = 0;
|
||||
commands[6] = static_cast<uint32_t>(address);
|
||||
commands[7] = static_cast<uint32_t>(address >> 32u);
|
||||
commands[8] = 33;
|
||||
|
||||
processor.ResetDeCe();
|
||||
Pm4Execution execution;
|
||||
Require("Pm4CeCompletion", "wait",
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Blocked &&
|
||||
suffix == 0,
|
||||
"DE did not wait for an active CE stream");
|
||||
|
||||
std::array<uint32_t, 2> ce_increment{0xc0008400u, 1};
|
||||
Pm4Execution ce_execution;
|
||||
Require("Pm4CeCompletion", "CE increment",
|
||||
processor.Process(ce_execution, ce_increment) ==
|
||||
Pm4ProcessResult::Complete,
|
||||
"CE counter increment did not complete");
|
||||
Require(
|
||||
"Pm4CeCompletion", "counter gate",
|
||||
processor.Process(execution, commands) == Pm4ProcessResult::Complete &&
|
||||
suffix == 33,
|
||||
"DE did not resume after CE advanced or failed to increment its counter");
|
||||
|
||||
suffix = 0;
|
||||
Pm4Execution balanced_execution;
|
||||
Require("Pm4CeCompletion", "balanced wait",
|
||||
processor.Process(balanced_execution, commands) ==
|
||||
Pm4ProcessResult::Blocked &&
|
||||
suffix == 0,
|
||||
"balanced CE/DE counters did not gate the next DE packet");
|
||||
processor.SetCeComplete(true);
|
||||
Require("Pm4CeCompletion", "stream complete",
|
||||
processor.Process(balanced_execution, commands) ==
|
||||
Pm4ProcessResult::Complete &&
|
||||
suffix == 33,
|
||||
"DE remained blocked after the CE stream completed");
|
||||
std::printf("[host] %-32s ok\n", "Pm4CeCompletion");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -50744,6 +50774,10 @@ int main(int argc, char **argv) {
|
||||
CheckWaitUntilSafeForRendering();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--flip-only") == 0) {
|
||||
CheckPm4Flip();
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--gpu-command-lane-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
vulkan.CheckGpuCommandLane();
|
||||
@@ -50752,7 +50786,6 @@ int main(int argc, char **argv) {
|
||||
CheckPm4IndirectControlFlow(vulkan.RuntimeRenderer());
|
||||
CheckPm4WaitResume(vulkan.RuntimeRenderer());
|
||||
CheckPm4RewindResume(vulkan.RuntimeRenderer());
|
||||
CheckPm4CeCompletion(vulkan.RuntimeRenderer());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--suspend-point-only") == 0) {
|
||||
@@ -51221,7 +51254,6 @@ int main(int argc, char **argv) {
|
||||
CheckPm4IndirectControlFlow(vulkan.RuntimeRenderer());
|
||||
CheckPm4WaitResume(vulkan.RuntimeRenderer());
|
||||
CheckPm4RewindResume(vulkan.RuntimeRenderer());
|
||||
CheckPm4CeCompletion(vulkan.RuntimeRenderer());
|
||||
CheckEmbeddedFetchVertexOffset();
|
||||
CheckEmbeddedFetchLaneSpill();
|
||||
CheckTessellationPrograms();
|
||||
|
||||
Reference in New Issue
Block a user