diff --git a/CMakeLists.txt b/CMakeLists.txt index 90be68252..29cd63b41 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -694,6 +694,8 @@ if(BUILD_TESTING) COMMAND $ --gpu-command-lane-only) add_test(NAME wait_until_safe_for_rendering COMMAND $ --wait-until-safe-for-rendering-only) + add_test(NAME pm4_flip + COMMAND $ --flip-only) add_test(NAME depth_bits COMMAND $ --depth-bits-only) add_test(NAME msaa_storage diff --git a/src/graphics/guest_gpu/command_processor/commandProcessor.h b/src/graphics/guest_gpu/command_processor/commandProcessor.h index 1eb1d0218..36efb52cb 100644 --- a/src/graphics/guest_gpu/command_processor/commandProcessor.h +++ b/src/graphics/guest_gpu/command_processor/commandProcessor.h @@ -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 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 commands); void ProcessIndirectBuffer(std::span 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 - 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; diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp index 7d09ce240..b35ee4bea 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.cpp @@ -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; diff --git a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h index 7979ebcd6..32f288971 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Dispatch.h +++ b/src/graphics/guest_gpu/command_processor/pm4Dispatch.h @@ -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); diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index 62e95890a..788b45142 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -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(buffer[2] | (static_cast(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(buffer[1] | (static_cast(buffer[2] & 0xffffu) << 32u)); - uint64_t value = (buffer[3] | (static_cast(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(buffer[1] | (static_cast(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(buffer[0]); - f.index = static_cast(buffer[1]); - f.flip_mode = static_cast(buffer[2]); - f.flip_arg = static_cast(buffer[3] | (static_cast(buffer[4]) << 32u)); - - cp.SetFlip(f); - cp.Flip(); + cp.Flip(static_cast(buffer[0]), static_cast(buffer[1]), static_cast(buffer[2]), + static_cast(buffer[3] | (static_cast(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(buffer[1] | (static_cast(buffer[2]) << 32u)); - uint32_t value = buffer[3]; - cp.Flip(addr, value); - break; - } - case 0x68750781: { - auto* addr = - reinterpret_cast(buffer[1] | (static_cast(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(value), - interrupt_selector, interrupt_context_id); + cp.WriteAtEndOfPipe32(eop_event_type, cache_action, event_index, event_source, dst_gpu_addr, + static_cast(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(value), - interrupt_selector, interrupt_context_id); + cp.WriteAtEndOfPipe32(eop_event_type, cache_action, event_index, event_source, dst_gpu_addr, + static_cast(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(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++) { diff --git a/src/graphics/guest_gpu/graphicsRun.cpp b/src/graphics/guest_gpu/graphicsRun.cpp index 945bdf3a4..ffcc9b95d 100644 --- a/src/graphics/guest_gpu/graphicsRun.cpp +++ b/src/graphics/guest_gpu/graphicsRun.cpp @@ -127,16 +127,14 @@ void GuestGpu::SendCommandSync(Common::UniqueFunction&& command) { done.acquire(); } -void GuestGpu::Submit(std::span draw_commands, - std::span constant_commands) { - if (draw_commands.empty()) { +void GuestGpu::Submit(std::span 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(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(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(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(buffer), num_dw); - for (uint32_t i = 0; i < std::min(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(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(buffer), num_dw); + for (uint32_t i = 0; i < std::min(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 -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(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(dst_gpu_addr), log_width, static_cast(value)); + bits, eop_event_type, cache_action, event_index, event_write_source, + interrupt_selector, interrupt_context_id, reinterpret_cast(dst_gpu_addr), + log_width, static_cast(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(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(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) { diff --git a/src/graphics/guest_gpu/graphicsRun.h b/src/graphics/guest_gpu/graphicsRun.h index 399c56356..e0868c922 100644 --- a/src/graphics/guest_gpu/graphicsRun.h +++ b/src/graphics/guest_gpu/graphicsRun.h @@ -35,8 +35,7 @@ public: void Wake(); // Submitted command memory is borrowed and must remain valid until GPU execution completes. - void Submit(std::span draw_commands, - std::span constant_commands); + void Submit(std::span commands); void SubmitCompute(uint32_t queue, std::span 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 commands; - std::span 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); diff --git a/src/graphics/guest_gpu/hardwareContext.h b/src/graphics/guest_gpu/hardwareContext.h index 97977fe2c..14534e4b7 100644 --- a/src/graphics/guest_gpu/hardwareContext.h +++ b/src/graphics/guest_gpu/hardwareContext.h @@ -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; } diff --git a/src/graphics/guest_gpu/pm4.cpp b/src/graphics/guest_gpu/pm4.cpp index a77efe018..ed75e680a 100644 --- a/src/graphics/guest_gpu/pm4.cpp +++ b/src/graphics/guest_gpu/pm4.cpp @@ -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"; diff --git a/src/graphics/guest_gpu/pm4.h b/src/graphics/guest_gpu/pm4.h index 74dd4ed7f..71fa8b285 100644 --- a/src/graphics/guest_gpu/pm4.h +++ b/src/graphics/guest_gpu/pm4.h @@ -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; diff --git a/src/libs/agc.cpp b/src/libs/agc.cpp index e7460979a..518422b4b 100644 --- a/src/libs/agc.cpp +++ b/src/libs/agc.cpp @@ -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(vaddr & 0xffffffffu); cmd[4] = static_cast((vaddr >> 32u) & 0xffffffffu); - } else if (op == Pm4::IT_EVENT_WRITE_EOP) { - cmd[2] = static_cast(vaddr & 0xffffffffu); - cmd[3] = (cmd[3] & 0xffff0000u) | static_cast((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) { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index fd81aa2f0..c6fb04280 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -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 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(address(&suffix)); commands[15] = static_cast(address(&suffix) >> 32u); commands[16] = 22; - gpu.Submit(commands, {}); + gpu.Submit(commands); std::binary_semaphore ordered_started{0}; std::atomic 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(code.data()), @@ -10920,7 +10921,7 @@ public: output.fields[3] = DstSel(4, 5, 6, 7) | (static_cast(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(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 actual{}; @@ -11270,8 +11271,8 @@ public: out.fields[3] = DstSel(4, 5, 6, 7) | (static_cast(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(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(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(parameters), HW::UserSgprType::Unknown); - shaders.SetCsUserSgpr(1, static_cast(parameters >> 32u), HW::UserSgprType::Unknown); + shaders.SetCsUserSgpr(0, static_cast(parameters)); + shaders.SetCsUserSgpr(1, static_cast(parameters >> 32u)); const ShaderBufferResource table_buffer{{static_cast(table_address), static_cast(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(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 args{std::bit_cast(1.0f), 0, 0, std::bit_cast(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(&attribute)}; shaders.SetGsShaderResource2({.user_sgpr = 4}); for (u32 i = 0; i < 4; i++) { - shaders.SetGsUserSgpr(i, static_cast(tables[i / 2] >> (i % 2 * 32)), - HW::UserSgprType::Unknown); + shaders.SetGsUserSgpr(i, static_cast(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 indexed_packet{ KYTY_PM4(5, Pm4::IT_DRAW_INDEX_INDIRECT, 0), 0, @@ -49595,25 +49598,18 @@ void CheckPm4IndirectControlFlow(RenderContext &renderer) { Gen5::AgcCbNop(reinterpret_cast(&payload_dcb), 3) == payload.data() && payload == std::array{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 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 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 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(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 results{}; + constexpr int64_t flip_arg = 0x777; + std::array commands{}; + const auto dump = [&](size_t at, const uint64_t *counter) { + const auto address = reinterpret_cast(counter); + commands[at] = KYTY_PM4(4, Pm4::IT_EVENT_WRITE, Pm4::R_ZERO); + commands[at + 1] = 0x139u; + commands[at + 2] = static_cast(address); + commands[at + 3] = static_cast(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(handle); + commands[10] = static_cast(-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(&suffix); - - std::array 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(address); - commands[7] = static_cast(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 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();