diff --git a/src/graphics/guest_gpu/command_processor/commandProcessor.h b/src/graphics/guest_gpu/command_processor/commandProcessor.h index bb17aa4be..01d54beb9 100644 --- a/src/graphics/guest_gpu/command_processor/commandProcessor.h +++ b/src/graphics/guest_gpu/command_processor/commandProcessor.h @@ -7,6 +7,7 @@ #include "graphics/host_gpu/renderer/renderContext.h" #include +#include #include namespace Libs::Graphics { @@ -30,10 +31,9 @@ private: friend class CommandProcessor; struct BufferCursor { - uint32_t* next_packet = nullptr; - uint32_t remaining_dw = 0; - uint32_t total_dw = 0; - uint32_t deferred_advance_dw = 0; + std::span commands; + uint32_t offset_dw = 0; + uint32_t deferred_advance_dw = 0; }; std::vector m_buffer_stack; @@ -50,7 +50,8 @@ public: int64_t flip_arg = 0; }; - explicit CommandProcessor(RenderContext& renderer): m_renderer(renderer) {} + CommandProcessor(RenderContext& renderer, int interrupt_event_id) + : m_renderer(renderer), m_interrupt_event_id(interrupt_event_id) {} ~CommandProcessor() = default; KYTY_CLASS_NO_COPY(CommandProcessor); @@ -131,13 +132,14 @@ public: const volatile void* address, uint32_t count_in_dwords); [[nodiscard]] bool ShouldSkipPredicatedPackets() const { return m_predicate_skip; } - Pm4ProcessResult Process(Pm4Execution& execution, uint32_t* buffer, uint32_t size_dw); - void ProcessIndirectBuffer(uint32_t* buffer, uint32_t size_dw); + Pm4ProcessResult Process(Pm4Execution& execution, std::span commands); + void ProcessIndirectBuffer(std::span commands); 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 @@ -177,10 +179,11 @@ private: uint32_t m_const_ram[0x3000] = {0}; - FlipInfo m_flip; - uint64_t m_submit_id = 0; - uint64_t m_synthetic_occlusion_counter = 0; - bool m_predicate_skip = false; + FlipInfo m_flip; + const int m_interrupt_event_id; + uint64_t m_submit_id = 0; + uint64_t m_synthetic_occlusion_counter = 0; + bool m_predicate_skip = false; }; } // namespace Libs::Graphics diff --git a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp index b22bb4f45..6e8569393 100644 --- a/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp +++ b/src/graphics/guest_gpu/command_processor/pm4Handlers.cpp @@ -1859,11 +1859,11 @@ KYTY_CP_OP_PARSER(CpOpBranch) { uint64_t reference = buffer[5] | (static_cast(buffer[6]) << 32u); uint32_t mode = buffer[0] & 0x3u; uint32_t function = (buffer[0] >> 8u) & 0x7u; - auto* then_buffer = reinterpret_cast((buffer[7] & 0xfffffffcu) | - (static_cast(buffer[8]) << 32u)); + auto* then_buffer = reinterpret_cast( + (buffer[7] & 0xfffffffcu) | (static_cast(buffer[8]) << 32u)); uint32_t then_num_dw = buffer[9] & 0xfffffu; - auto* else_buffer = reinterpret_cast((buffer[10] & 0xfffffffcu) | - (static_cast(buffer[11]) << 32u)); + auto* else_buffer = reinterpret_cast( + (buffer[10] & 0xfffffffcu) | (static_cast(buffer[11]) << 32u)); uint32_t else_num_dw = buffer[12] & 0xfffffu; EXIT_NOT_IMPLEMENTED(compare_addr == nullptr); @@ -1877,10 +1877,10 @@ KYTY_CP_OP_PARSER(CpOpBranch) { reinterpret_cast(else_buffer), else_num_dw); if (take_then) { - cp.ProcessIndirectBuffer(then_buffer, then_num_dw); + cp.ProcessIndirectBuffer({then_buffer, then_num_dw}); } else if (mode == 2 && else_num_dw != 0) { EXIT_NOT_IMPLEMENTED(else_buffer == nullptr); - cp.ProcessIndirectBuffer(else_buffer, else_num_dw); + cp.ProcessIndirectBuffer({else_buffer, else_num_dw}); } return payload_dw; @@ -2321,7 +2321,7 @@ KYTY_CP_OP_PARSER(CpOpIndirectBuffer) { } auto* indirect_buffer = - reinterpret_cast(buffer[0] | (static_cast(buffer[1]) << 32u)); + reinterpret_cast(buffer[0] | (static_cast(buffer[1]) << 32u)); uint32_t indirect_num_dw = control & 0xfffffu; static std::atomic indirect_log_count {0}; if (indirect_log_count.fetch_add(1) < 128) { @@ -2341,7 +2341,7 @@ KYTY_CP_OP_PARSER(CpOpIndirectBuffer) { GraphicsDbgDumpDcb("ci", indirect_num_dw, indirect_buffer); - cp.ProcessIndirectBuffer(indirect_buffer, indirect_num_dw); + cp.ProcessIndirectBuffer({indirect_buffer, indirect_num_dw}); return 3; } diff --git a/src/graphics/guest_gpu/graphicsRun.cpp b/src/graphics/guest_gpu/graphicsRun.cpp index 05d5f91de..3fbeaee17 100644 --- a/src/graphics/guest_gpu/graphicsRun.cpp +++ b/src/graphics/guest_gpu/graphicsRun.cpp @@ -66,17 +66,10 @@ static bool GraphicsRunDebugDumpEnabled() { Config::GetPrintfDirection() != Config::OutputDirection::Silent; } -GuestGpu::OwnedCmdBuffer::OwnedCmdBuffer(const uint32_t* data, uint32_t count) { - EXIT_IF(data == nullptr && count != 0); - if (count != 0) { - m_words.assign(data, data + count); - } -} - GuestGpu::GuestGpu(RenderContext& renderer): m_renderer(renderer) { EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); GraphicsInitJmpTables(); - m_gfx_cp = std::make_unique(renderer); + m_gfx_cp = std::make_unique(renderer, 0); m_thread = std::jthread(ThreadRun, this); } @@ -148,39 +141,33 @@ void GuestGpu::SendCommandSync(Common::UniqueFunction&& command) { done.acquire(); } -void GuestGpu::Submit(uint32_t* cmd_draw_buffer, uint32_t num_draw_dw, uint32_t* cmd_const_buffer, - uint32_t num_const_dw, bool trigger_agc_interrupt_on_done) { - if (num_draw_dw == 0) { +void GuestGpu::Submit(std::span draw_commands, + std::span constant_commands) { + if (draw_commands.empty()) { return; } - EXIT_IF(cmd_draw_buffer == nullptr); GpuMutexLock lock(m_submission_mutex); Submission submission; - submission.type = SubmissionType::Graphics; - submission.queue_id = 0; - submission.commands = OwnedCmdBuffer(cmd_draw_buffer, num_draw_dw); - submission.constant_commands = OwnedCmdBuffer(cmd_const_buffer, num_const_dw); - submission.trigger_agc_interrupt_on_done = trigger_agc_interrupt_on_done; - submission.reset_processor = m_graphics_done; - m_graphics_done = false; + submission.type = SubmissionType::Graphics; + submission.queue_id = 0; + submission.commands = draw_commands; + submission.constant_commands = constant_commands; + submission.reset_processor = m_graphics_done; + m_graphics_done = false; Enqueue(std::move(submission)); } -void GuestGpu::SubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw, - bool trigger_agc_interrupt_on_done) { - EXIT_IF(cmd_buffer == nullptr || num_dw == 0); +void GuestGpu::SubmitCompute(uint32_t queue, std::span commands) { + EXIT_IF(commands.empty()); GpuMutexLock lock(m_submission_mutex); - constexpr uint32_t compute_queue_base = 0x20u; - EXIT_NOT_IMPLEMENTED(queue < compute_queue_base || - queue >= compute_queue_base + ComputeQueueCount); + EXIT_NOT_IMPLEMENTED(queue < ComputeQueueBase || queue >= ComputeQueueBase + ComputeQueueCount); - const auto compute_queue = queue - compute_queue_base; + const auto compute_queue = queue - ComputeQueueBase; Submission submission; - submission.type = SubmissionType::Compute; - submission.queue_id = 1 + compute_queue; - submission.commands = OwnedCmdBuffer(cmd_buffer, num_dw); - submission.trigger_agc_interrupt_on_done = trigger_agc_interrupt_on_done; + submission.type = SubmissionType::Compute; + submission.queue_id = 1 + compute_queue; + submission.commands = commands; Enqueue(std::move(submission)); } @@ -215,7 +202,7 @@ CommandProcessor& GuestGpu::GetProcessor(uint32_t queue_id) { } auto& processor = m_compute_cp[queue_id - 1]; if (processor == nullptr) { - processor = std::make_unique(m_renderer); + processor = std::make_unique(m_renderer, ComputeQueueBase + queue_id - 1); } return *processor; } @@ -583,21 +570,20 @@ bool GuestGpu::Process(Submission& submission) { switch (submission.type) { case SubmissionType::Graphics: { bool progressed = false; - submission.constant_complete |= submission.constant_commands.Empty(); + 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.Data(), - submission.constant_commands.Size()) == Pm4ProcessResult::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.Data(), - submission.commands.Size()) == Pm4ProcessResult::Complete; + cp.Process(submission.command_execution, submission.commands) == + Pm4ProcessResult::Complete; round_progress |= submission.command_execution.MadeProgress(); } progressed |= round_progress; @@ -614,14 +600,11 @@ bool GuestGpu::Process(Submission& submission) { } else if (complete) { m_renderer.GetGpuResources().RunGarbageCollector(); } - if (complete && submission.trigger_agc_interrupt_on_done) { - m_renderer.TriggerEopEvent(0); - } break; } case SubmissionType::Compute: { - const auto num_dw = submission.commands.Size(); - auto* buffer = submission.commands.Data(); + 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", @@ -633,7 +616,7 @@ bool GuestGpu::Process(Submission& submission) { if (first_slice) { GraphicsDbgDumpDcb("cc", num_dw, buffer); } - complete = cp.Process(submission.command_execution, buffer, num_dw) == + complete = cp.Process(submission.command_execution, submission.commands) == Pm4ProcessResult::Complete; if (submission.command_execution.MadeProgress()) { if (complete) { @@ -643,9 +626,6 @@ bool GuestGpu::Process(Submission& submission) { } else if (complete) { m_renderer.GetGpuResources().RunGarbageCollector(); } - if (complete && submission.trigger_agc_interrupt_on_done) { - Sync::TriggerAgcUserInterrupt(); - } break; } case SubmissionType::FlipPreparation: @@ -657,12 +637,13 @@ bool GuestGpu::Process(Submission& submission) { return complete; } -Pm4ProcessResult CommandProcessor::Process(Pm4Execution& execution, uint32_t* buffer, - uint32_t size_dw) { +Pm4ProcessResult CommandProcessor::Process(Pm4Execution& execution, + std::span commands) { KYTY_PROFILER_BLOCK("CommandProcessor::Process"); EXIT_IF(g_current_execution != nullptr); - if (execution.m_buffer_stack.empty() && size_dw != 0) { - execution.m_buffer_stack.push_back({buffer, size_dw, size_dw, 0}); + EXIT_IF(commands.size() > UINT32_MAX); + if (execution.m_buffer_stack.empty() && !commands.empty()) { + execution.m_buffer_stack.push_back({commands}); } execution.m_suspended = false; execution.m_made_progress = false; @@ -687,14 +668,14 @@ Pm4ProcessResult CommandProcessor::Process(Pm4Execution& execution, uint32_t* bu : Pm4ProcessResult::Blocked; } -void CommandProcessor::ProcessIndirectBuffer(uint32_t* buffer, uint32_t size_dw) { +void CommandProcessor::ProcessIndirectBuffer(std::span commands) { EXIT_IF(g_current_execution == nullptr); - if (size_dw == 0) { + if (commands.empty()) { return; } auto& execution = *g_current_execution; const auto stop_depth = execution.m_buffer_stack.size(); - execution.m_buffer_stack.push_back({buffer, size_dw, size_dw, 0}); + execution.m_buffer_stack.push_back({commands}); ProcessPm4(execution, stop_depth); } @@ -710,29 +691,28 @@ void CommandProcessor::ProcessPm4(Pm4Execution& execution, size_t stop_depth) { } const auto buffer_index = execution.m_buffer_stack.size() - 1; auto& cursor = execution.m_buffer_stack[buffer_index]; + EXIT_IF(cursor.offset_dw > cursor.commands.size()); if (cursor.deferred_advance_dw != 0) { - EXIT_IF(cursor.deferred_advance_dw > cursor.remaining_dw); - cursor.next_packet += cursor.deferred_advance_dw; - cursor.remaining_dw -= cursor.deferred_advance_dw; + EXIT_IF(cursor.deferred_advance_dw > cursor.commands.size() - cursor.offset_dw); + cursor.offset_dw += cursor.deferred_advance_dw; cursor.deferred_advance_dw = 0; execution.m_made_progress = true; continue; } - if (cursor.remaining_dw == 0) { + if (cursor.offset_dw == cursor.commands.size()) { execution.m_buffer_stack.pop_back(); continue; } - auto* const packet = cursor.next_packet; - const auto remaining_dw = cursor.remaining_dw; - const auto total_dw = cursor.total_dw; - const auto packet_header = packet[0]; - const auto opcode = (packet_header >> 8u) & 0xffu; + const auto* const packet = cursor.commands.data() + cursor.offset_dw; + const auto total_dw = static_cast(cursor.commands.size()); + const auto remaining_dw = total_dw - cursor.offset_dw; + const auto packet_header = packet[0]; + const auto opcode = (packet_header >> 8u) & 0xffu; EXIT_NOT_IMPLEMENTED(remaining_dw > total_dw); if (packet_header == 0x80000000u) { - cursor.next_packet++; - cursor.remaining_dw--; + cursor.offset_dw++; execution.m_made_progress = true; continue; } @@ -767,8 +747,7 @@ void CommandProcessor::ProcessPm4(Pm4Execution& execution, size_t stop_depth) { dst, val, packet[1], packet[2]); } } - cursor.next_packet += packet_dw; - cursor.remaining_dw -= packet_dw; + cursor.offset_dw += packet_dw; execution.m_made_progress = true; continue; } @@ -801,8 +780,7 @@ void CommandProcessor::ProcessPm4(Pm4Execution& execution, size_t stop_depth) { return; } EXIT_IF(execution.m_buffer_stack.size() != buffer_index + 1); - execution.m_buffer_stack[buffer_index].next_packet += packet_dw; - execution.m_buffer_stack[buffer_index].remaining_dw -= packet_dw; + execution.m_buffer_stack[buffer_index].offset_dw += packet_dw; execution.m_made_progress = true; } } @@ -1245,7 +1223,14 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr switch (interrupt_selector) { case 0x00: case 0x03: with_interrupt = false; break; - case 0x01: Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), interrupt_context_id); return; + case 0x01: + if (!IsAsyncComputeQueue()) { + Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), m_interrupt_event_id, + interrupt_context_id); + return; + } + with_interrupt = true; + break; case 0x02: with_interrupt = true; break; default: EXIT("unknown interrupt_selector\n"); } @@ -1258,10 +1243,11 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr if (with_interrupt) { if (with_writeback) { Sync::WriteAtEndOfPipeWithInterruptWriteBack32(m_submit_id, CurrentBuffer(), dst, - data, interrupt_context_id); + data, m_interrupt_event_id, + interrupt_context_id); } else { Sync::WriteAtEndOfPipeWithInterrupt32(m_submit_id, CurrentBuffer(), dst, data, - interrupt_context_id); + m_interrupt_event_id, interrupt_context_id); } } else if (with_writeback) { Sync::WriteAtEndOfPipeWithWriteBack32(m_submit_id, CurrentBuffer(), dst, data); @@ -1281,7 +1267,7 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr Sync::WriteAtEndOfPipeGds32(m_submit_id, CurrentBuffer(), dst, value & 0xffffu, value >> 16u); if (with_interrupt) { - m_renderer.TriggerEopEvent(interrupt_context_id); + m_renderer.TriggerInterrupt(m_interrupt_event_id, interrupt_context_id); } return; } @@ -1307,10 +1293,12 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr if (with_interrupt) { if (with_writeback) { Sync::WriteAtEndOfPipeWithInterruptWriteBack64( - m_submit_id, CurrentBuffer(), dst, value, interrupt_context_id); + m_submit_id, CurrentBuffer(), dst, value, m_interrupt_event_id, + interrupt_context_id); } else { Sync::WriteAtEndOfPipeWithInterrupt64(m_submit_id, CurrentBuffer(), dst, - value, interrupt_context_id); + value, m_interrupt_event_id, + interrupt_context_id); } } else if (with_writeback) { Sync::WriteAtEndOfPipeWithWriteBack64(m_submit_id, CurrentBuffer(), dst, @@ -1389,26 +1377,35 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr case 0x04: if constexpr (sizeof(T) == sizeof(uint64_t)) { const auto clock = Sync::ReadReferenceClock(); - std::memcpy(dst_gpu_addr, &clock, sizeof(clock)); + auto* dst = static_cast(dst_gpu_addr); + std::memcpy(dst, &clock, sizeof(clock)); switch (cache_action) { case 0x00: - if (((eop_event_type == 0x04 && event_index == 0x05) || - (eop_event_type == 0x28 && event_index == 0x00)) && - !with_interrupt) { - Sync::WriteAtEndOfPipeClockCounter(m_submit_id, CurrentBuffer(), - static_cast(dst_gpu_addr), - clock); + if ((eop_event_type == 0x04 && event_index == 0x05) || + (eop_event_type == 0x28 && event_index == 0x00)) { + if (with_interrupt) { + Sync::WriteAtEndOfPipeWithInterrupt64( + m_submit_id, CurrentBuffer(), dst, clock, m_interrupt_event_id, + interrupt_context_id); + } else { + Sync::WriteAtEndOfPipeClockCounter(m_submit_id, CurrentBuffer(), + dst, clock); + } return; } break; case 0x38: - if (((eop_event_type == 0x04 && - (event_index == 0x00 || event_index == 0x05)) || - (eop_event_type == 0x28 && event_index == 0x00)) && - !with_interrupt) { - Sync::WriteAtEndOfPipeClockCounterWithWriteBack( - m_submit_id, CurrentBuffer(), static_cast(dst_gpu_addr), - clock); + if ((eop_event_type == 0x04 && + (event_index == 0x00 || event_index == 0x05)) || + (eop_event_type == 0x28 && event_index == 0x00)) { + if (with_interrupt) { + Sync::WriteAtEndOfPipeWithInterruptWriteBack64( + m_submit_id, CurrentBuffer(), dst, clock, m_interrupt_event_id, + interrupt_context_id); + } else { + Sync::WriteAtEndOfPipeClockCounterWithWriteBack( + m_submit_id, CurrentBuffer(), dst, clock); + } return; } break; @@ -1465,7 +1462,7 @@ void CommandProcessor::EmitGlobalBarrier() { void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id) { CheckBuffer(); - Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), interrupt_context_id); + Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), m_interrupt_event_id, interrupt_context_id); } void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index, @@ -1604,7 +1601,7 @@ void CommandProcessor::FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache m_flip.flip_arg); Sync::WriteAtEndOfPipeWithInterruptWriteBackFlip32( m_submit_id, command, static_cast(dst_gpu_addr), value, m_flip.handle, - m_flip.index, m_flip.flip_mode, m_flip.flip_arg, request); + m_flip.index, m_flip.flip_mode, m_flip.flip_arg, request, m_interrupt_event_id); GetScheduler().Flush(); } diff --git a/src/graphics/guest_gpu/graphicsRun.h b/src/graphics/guest_gpu/graphicsRun.h index 836cd6606..2cdf624df 100644 --- a/src/graphics/guest_gpu/graphicsRun.h +++ b/src/graphics/guest_gpu/graphicsRun.h @@ -13,8 +13,8 @@ #include #include #include +#include #include -#include namespace Libs::Graphics { @@ -31,12 +31,12 @@ public: void SendCommand(Common::UniqueFunction&& command); void SendCommandSync(Common::UniqueFunction&& command); - void Submit(uint32_t* draw_commands, uint32_t draw_size_dw, uint32_t* constant_commands, - uint32_t constant_size_dw, bool trigger_agc_interrupt_on_done = false); - void SubmitCompute(uint32_t queue, uint32_t* commands, uint32_t size_dw, - bool trigger_agc_interrupt_on_done = false); - void SubmitFlipPreparation(uint64_t request_id); - void Done(); + // Submitted command memory is borrowed and must remain valid until GPU execution completes. + void Submit(std::span draw_commands, + std::span constant_commands); + void SubmitCompute(uint32_t queue, std::span commands); + void SubmitFlipPreparation(uint64_t request_id); + void Done(); [[nodiscard]] int GetFrameNum() const; [[nodiscard]] static bool IsGpuThread() noexcept; @@ -45,39 +45,24 @@ private: static constexpr uint32_t ComputePipeCount = 7; static constexpr uint32_t QueuesPerComputePipe = 8; static constexpr uint32_t ComputeQueueCount = ComputePipeCount * QueuesPerComputePipe; + static constexpr uint32_t ComputeQueueBase = 0x20; static constexpr uint32_t QueueCount = 1 + ComputeQueueCount; - class OwnedCmdBuffer { - public: - OwnedCmdBuffer() = default; - explicit OwnedCmdBuffer(const uint32_t* data, uint32_t count); - - [[nodiscard]] bool Empty() const noexcept { return m_words.empty(); } - [[nodiscard]] uint32_t Size() const noexcept { - return static_cast(m_words.size()); - } - [[nodiscard]] uint32_t* Data() noexcept { return m_words.data(); } - - private: - std::vector m_words; - }; - enum class SubmissionType { Graphics, Compute, FlipPreparation }; struct Submission { - SubmissionType type = SubmissionType::Graphics; - uint32_t queue_id = 0; - OwnedCmdBuffer commands; - OwnedCmdBuffer constant_commands; - Pm4Execution command_execution; - Pm4Execution constant_execution; - bool trigger_agc_interrupt_on_done = false; - bool reset_processor = false; - bool started = false; - bool command_complete = false; - bool constant_complete = false; - bool blocked = false; - uint64_t flip_request_id = 0; + SubmissionType type = SubmissionType::Graphics; + uint32_t queue_id = 0; + std::span commands; + std::span constant_commands; + Pm4Execution command_execution; + Pm4Execution constant_execution; + bool reset_processor = false; + bool started = false; + bool command_complete = false; + bool constant_complete = false; + bool blocked = false; + uint64_t flip_request_id = 0; }; void Enqueue(Submission submission); diff --git a/src/graphics/guest_gpu/pm4.cpp b/src/graphics/guest_gpu/pm4.cpp index fa5cb816e..551da30a2 100644 --- a/src/graphics/guest_gpu/pm4.cpp +++ b/src/graphics/guest_gpu/pm4.cpp @@ -100,7 +100,7 @@ constexpr auto g_opcode_names = MakeOpcodeNames(); } // namespace -void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t start_dw, +void DumpPm4PacketStream(Common::File* file, const uint32_t* cmd_buffer, uint32_t start_dw, uint32_t num_dw) { // db_dump(); @@ -143,9 +143,9 @@ void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t star if ((op == IT_SET_CONTEXT_REG_INDIRECT || op == IT_SET_SH_REG_INDIRECT || op == IT_SET_UCONFIG_REG_INDIRECT) && len == 4) { - auto* indirect_buffer = - reinterpret_cast((static_cast(cmd[0]) & 0xfffffffcu) | - (static_cast(cmd[1]) << 32u)); + auto* indirect_buffer = reinterpret_cast( + (static_cast(cmd[0]) & 0xfffffffcu) | + (static_cast(cmd[1]) << 32u)); const uint32_t indirect_num_regs = cmd[3] & 0x3fffu; for (uint32_t i = 0; indirect_buffer != nullptr && i < indirect_num_regs; diff --git a/src/graphics/guest_gpu/pm4.h b/src/graphics/guest_gpu/pm4.h index 7630a6182..16e0e5276 100644 --- a/src/graphics/guest_gpu/pm4.h +++ b/src/graphics/guest_gpu/pm4.h @@ -1088,7 +1088,7 @@ constexpr uint32_t UC_NOP = 0x80003FFF; constexpr uint32_t UC_NUM = 0x3FFF + 1; -void DumpPm4PacketStream(Common::File* file, uint32_t* cmd_buffer, uint32_t start_dw, +void DumpPm4PacketStream(Common::File* file, const uint32_t* cmd_buffer, uint32_t start_dw, uint32_t num_dw); } // namespace Libs::Graphics::Pm4 diff --git a/src/graphics/host_gpu/renderer/renderContext.cpp b/src/graphics/host_gpu/renderer/renderContext.cpp index 5ddf30f1f..7111962c6 100644 --- a/src/graphics/host_gpu/renderer/renderContext.cpp +++ b/src/graphics/host_gpu/renderer/renderContext.cpp @@ -4,7 +4,6 @@ #include "common/logging/log.h" #include "graphics/guest_gpu/graphicsRun.h" #include "graphics/presentation/videoOut.h" -#include "kernel/pthread.h" #include "libs/errno.h" #include @@ -56,60 +55,54 @@ VideoOut::VideoOutDriver& RenderContext::GetVideoOut() const { return *m_video_out; } -void RenderContext::AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) { - auto queue = LibKernel::EventQueue::KernelPinEqueue(eq); - if (!queue) { +void RenderContext::AddInterruptEq(LibKernel::EventQueue::KernelEqueue eq, int event_id) { + Common::LockGuard lock(m_interrupt_mutex); + + auto it = std::find_if( + m_interrupt_eqs.begin(), m_interrupt_eqs.end(), + [eq, event_id](const auto& entry) { return entry.eq == eq && entry.event_id == event_id; }); + if (it != m_interrupt_eqs.end()) { return; } - Common::LockGuard lock(m_eop_mutex); - - auto it = std::find_if(m_eop_eqs.begin(), m_eop_eqs.end(), [eq, id](const auto& entry) { - return entry.eq == eq && entry.id == id; - }); - if (it != m_eop_eqs.end()) { - return; - } - - m_eop_eqs.push_back({eq, std::move(queue), id}); + m_interrupt_eqs.push_back({eq, event_id}); } -void RenderContext::DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id) { - Common::LockGuard lock(m_eop_mutex); +void RenderContext::DeleteInterruptEq(LibKernel::EventQueue::KernelEqueue eq, int event_id) { + Common::LockGuard lock(m_interrupt_mutex); - auto it = std::find_if(m_eop_eqs.begin(), m_eop_eqs.end(), [eq, id](const auto& entry) { - return entry.eq == eq && entry.id == id; - }); - if (it == m_eop_eqs.end()) { + auto it = std::find_if( + m_interrupt_eqs.begin(), m_interrupt_eqs.end(), + [eq, event_id](const auto& entry) { return entry.eq == eq && entry.event_id == event_id; }); + if (it == m_interrupt_eqs.end()) { return; } - m_eop_eqs.erase(it); + m_interrupt_eqs.erase(it); } -void RenderContext::TriggerEopEvent(uint32_t context_id) { - std::vector registrations; +void RenderContext::TriggerInterrupt(int event_id, uint32_t context_id) { + std::vector registrations; { - Common::LockGuard lock(m_eop_mutex); - registrations = m_eop_eqs; + Common::LockGuard lock(m_interrupt_mutex); + for (const auto& registration: m_interrupt_eqs) { + if (registration.event_id == event_id) { + registrations.push_back(registration); + } + } } for (const auto& registration: registrations) { const auto result = LibKernel::EventQueue::KernelTriggerEvent( - registration.eq, static_cast(registration.id), + registration.eq, static_cast(registration.event_id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS, reinterpret_cast(static_cast(context_id))); if (result == LibKernel::KERNEL_ERROR_EBADF || result == LibKernel::KERNEL_ERROR_ENOENT) { - DeleteEopEq(registration.eq, registration.id); + DeleteInterruptEq(registration.eq, registration.event_id); continue; } EXIT_NOT_IMPLEMENTED(result != OK); } - - auto tsc = LibKernel::KernelReadTsc(); - auto result = LibKernel::EventQueue::KernelTriggerUserEventForAll(AGC_USER_INTERRUPT_EVENT, - reinterpret_cast(tsc)); - EXIT_NOT_IMPLEMENTED(result != OK && result != LibKernel::KERNEL_ERROR_ENOENT); } } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/renderContext.h b/src/graphics/host_gpu/renderer/renderContext.h index ab56c2ca4..294b08e8a 100644 --- a/src/graphics/host_gpu/renderer/renderContext.h +++ b/src/graphics/host_gpu/renderer/renderContext.h @@ -23,7 +23,6 @@ class VideoOutDriver; namespace Libs::Graphics { -constexpr int AGC_USER_INTERRUPT_EVENT = 0x1800; class GuestGpu; class RenderContext { @@ -48,15 +47,14 @@ public: TextureCache& GetTextureCache() { return m_gpu_resources.GetTextureCache(); } RenderExecutor& GetRenderExecutor() { return m_render_executor; } - void AddEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); - void DeleteEopEq(LibKernel::EventQueue::KernelEqueue eq, int id); - void TriggerEopEvent(uint32_t context_id); + void AddInterruptEq(LibKernel::EventQueue::KernelEqueue eq, int event_id); + void DeleteInterruptEq(LibKernel::EventQueue::KernelEqueue eq, int event_id); + void TriggerInterrupt(int event_id, uint32_t context_id); private: - struct EopEqRegistration { - LibKernel::EventQueue::KernelEqueue eq = LibKernel::EventQueue::KERNEL_EQUEUE_INVALID; - LibKernel::EventQueue::KernelEqueueRef queue; - int id = 0; + struct InterruptEqRegistration { + LibKernel::EventQueue::KernelEqueue eq = LibKernel::EventQueue::KERNEL_EQUEUE_INVALID; + int event_id = 0; }; GraphicContext& m_graphics; @@ -70,8 +68,8 @@ private: std::unique_ptr m_gpu; VideoOut::VideoOutDriver* m_video_out = nullptr; - Common::Mutex m_eop_mutex; - std::vector m_eop_eqs; + Common::Mutex m_interrupt_mutex; + std::vector m_interrupt_eqs; }; } // namespace Libs::Graphics diff --git a/src/graphics/host_gpu/renderer/sync.cpp b/src/graphics/host_gpu/renderer/sync.cpp index e2afef6ed..c97e4cb0b 100644 --- a/src/graphics/host_gpu/renderer/sync.cpp +++ b/src/graphics/host_gpu/renderer/sync.cpp @@ -20,9 +20,7 @@ namespace Libs::Graphics::Sync { -constexpr int GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT = 0x00; -constexpr int GRAPHICS_EVENT_EOP = 0x40; -constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000; +constexpr uint64_t GRAPHICS_REFERENCE_CLOCK_FREQUENCY = 100000000; bool ScaleReferenceClock(uint64_t host_ticks, uint64_t host_frequency, uint64_t& value) { if (host_frequency == 0) { @@ -66,8 +64,9 @@ struct EndOfPipeSignal { std::array debug_args = {}; uint64_t debug_data = 0; std::optional destination; - EndOfPipeCompletion completion = EndOfPipeCompletion::None; - uint64_t completion_data = 0; + EndOfPipeCompletion completion = EndOfPipeCompletion::None; + uint64_t completion_data = 0; + int interrupt_event_id = 0; }; enum class EndOfPipeWriteSize : uint32_t { Dword = 4, Qword = 8 }; @@ -96,8 +95,10 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) { case EndOfPipeCompletion::None: return; case EndOfPipeCompletion::Interrupt: { const auto context_id = static_cast(signal.completion_data); - scheduler.DeferPriorityOperation( - [&renderer, context_id] { renderer.TriggerEopEvent(context_id); }); + const auto event_id = signal.interrupt_event_id; + scheduler.DeferPriorityOperation([&renderer, event_id, context_id] { + renderer.TriggerInterrupt(event_id, context_id); + }); return; } case EndOfPipeCompletion::Flip: { @@ -108,9 +109,10 @@ static void RecordEndOfPipeSignal(const EndOfPipeSignal& signal) { } case EndOfPipeCompletion::FlipAndInterrupt: { const auto request_id = signal.completion_data; - scheduler.DeferPriorityOperation([&renderer, request_id] { + const auto event_id = signal.interrupt_event_id; + scheduler.DeferPriorityOperation([&renderer, event_id, request_id] { renderer.GetVideoOut().CompleteFlip(request_id); - renderer.TriggerEopEvent(0); + renderer.TriggerInterrupt(event_id, 0); }); return; } @@ -135,7 +137,8 @@ static bool TriggersInterrupt(EndOfPipeWriteAction action) { static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer& buffer, uint64_t destination, uint64_t value, EndOfPipeWriteSize size, - EndOfPipeWriteAction action, uint32_t context_id = 0) { + EndOfPipeWriteAction action, int interrupt_event_id = 0, + uint32_t context_id = 0) { const auto width = static_cast(size); const auto value_low = static_cast(value); const auto value_high = static_cast(value >> 32u); @@ -150,18 +153,12 @@ static void RecordEndOfPipeWrite(uint64_t submit_id, CommandBuffer& buffer, uint .debug_data = destination, .destination = destination, .completion = interrupt ? EndOfPipeCompletion::Interrupt : EndOfPipeCompletion::None, - .completion_data = context_id != 0 ? context_id : value, + .completion_data = interrupt ? context_id : value, + .interrupt_event_id = interrupt_event_id, }; RecordEndOfPipeSignal(signal); } -void TriggerAgcUserInterrupt() { - auto tsc = LibKernel::KernelReadTsc(); - auto result = LibKernel::EventQueue::KernelTriggerUserEventForAll(AGC_USER_INTERRUPT_EVENT, - reinterpret_cast(tsc)); - EXIT_NOT_IMPLEMENTED(result != OK && result != LibKernel::KERNEL_ERROR_ENOENT); -} - void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, @@ -220,31 +217,35 @@ void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer, } void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer, - uint64_t* dst_gpu_addr, uint64_t value, + uint64_t* dst_gpu_addr, uint64_t value, int event_id, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::InterruptWriteBack, - context_id); + event_id, context_id); } void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer, - uint32_t* dst_gpu_addr, uint32_t value, + uint32_t* dst_gpu_addr, uint32_t value, int event_id, uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::InterruptWriteBack, - context_id); + event_id, context_id); } void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer, - uint64_t* dst_gpu_addr, uint64_t value, uint32_t context_id) { + uint64_t* dst_gpu_addr, uint64_t value, int event_id, + uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, - EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, context_id); + EndOfPipeWriteSize::Qword, EndOfPipeWriteAction::Interrupt, event_id, + context_id); } void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer, - uint32_t* dst_gpu_addr, uint32_t value, uint32_t context_id) { + uint32_t* dst_gpu_addr, uint32_t value, int event_id, + uint32_t context_id) { RecordEndOfPipeWrite(submit_id, buffer, reinterpret_cast(dst_gpu_addr), value, - EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, context_id); + EndOfPipeWriteSize::Dword, EndOfPipeWriteAction::Interrupt, event_id, + context_id); } uint64_t PrepareVideoOutFlip(CommandBuffer& buffer, int handle, int index, int flip_mode, @@ -270,18 +271,20 @@ uint64_t PrepareVideoOutFlip(CommandBuffer& buffer, int handle, int index, int f void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, - int64_t flip_arg, uint64_t request_id) { + int64_t flip_arg, uint64_t request_id, + int event_id) { const auto destination = reinterpret_cast(dst_gpu_addr); RecordEndOfPipeSignal({ - .buffer = &buffer, - .submit_id = submit_id, - .debug_operation = CommandBufferDebugOp::EopWriteBackFlip, - .debug_args = {static_cast(handle), static_cast(index), - static_cast(flip_mode), value}, - .debug_data = static_cast(flip_arg), - .destination = destination, - .completion = EndOfPipeCompletion::FlipAndInterrupt, - .completion_data = request_id, + .buffer = &buffer, + .submit_id = submit_id, + .debug_operation = CommandBufferDebugOp::EopWriteBackFlip, + .debug_args = {static_cast(handle), static_cast(index), + static_cast(flip_mode), value}, + .debug_data = static_cast(flip_arg), + .destination = destination, + .completion = EndOfPipeCompletion::FlipAndInterrupt, + .completion_data = request_id, + .interrupt_event_id = event_id, }); } @@ -316,36 +319,24 @@ void WriteAtEndOfPipeOnlyFlip(uint64_t submit_id, CommandBuffer& buffer, int han }); } -void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id) { +void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, int event_id, uint32_t context_id) { ValidateEndOfPipeSignal({.buffer = &buffer}); auto& renderer = buffer.GetContext(); auto& scheduler = renderer.GetCommandScheduler(); EXIT_IF(!scheduler.Active() || &buffer != &scheduler.Current()); scheduler.DeferPriorityOperation( - [&renderer, context_id] { renderer.TriggerEopEvent(context_id); }); + [&renderer, event_id, context_id] { renderer.TriggerInterrupt(event_id, context_id); }); } -static void EopEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) { +static void InterruptEventResetFunc(LibKernel::EventQueue::KernelEqueueEvent* event) { EXIT_IF(event == nullptr); event->triggered = false; event->event.fflags = 0; event->event.data = 0; } -static void EopEventDeleteFunc(LibKernel::EventQueue::KernelEqueue eq, - LibKernel::EventQueue::KernelEqueueEvent* event) { - EXIT_IF(event == nullptr); - EXIT_NOT_IMPLEMENTED(event->event.filter != LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); - if (event->event.ident == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || - event->event.ident == GRAPHICS_EVENT_EOP) { - auto* renderer = static_cast(event->filter.data); - EXIT_IF(renderer == nullptr); - renderer->DeleteEopEq(eq, static_cast(event->event.ident)); - } -} - -static void EopEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event, - void* trigger_data) { +static void InterruptEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event, + void* trigger_data) { EXIT_IF(event == nullptr); auto triggered_event = event->event; @@ -362,30 +353,30 @@ static void EopEventTriggerFunc(LibKernel::EventQueue::KernelEqueueEvent* event, int AddEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id, void* udata) { LibKernel::EventQueue::KernelEqueueEvent event; - event.triggered = false; - event.event.ident = static_cast(id); - event.event.filter = LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS; - event.event.udata = udata; - event.event.fflags = 0; - event.event.data = id; - event.filter.delete_event_func = EopEventDeleteFunc; - event.filter.reset_func = EopEventResetFunc; - event.filter.trigger_func = EopEventTriggerFunc; - event.filter.data = &renderer; + event.triggered = false; + event.event.ident = static_cast(id); + event.event.filter = LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS; + event.event.udata = udata; + event.event.fflags = 0; + event.event.data = id; + event.filter.reset_func = InterruptEventResetFunc; + event.filter.trigger_func = InterruptEventTriggerFunc; int result = LibKernel::EventQueue::KernelAddEvent(eq, event); - if (result == 0 && - (id == GRAPHICS_EVENT_QUEUED_GRAPHICS_INTERRUPT || id == GRAPHICS_EVENT_EOP)) { - renderer.AddEopEq(eq, id); + if (result == 0) { + renderer.AddInterruptEq(eq, id); } return result; } -int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id) { +int DeleteEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id) { int result = LibKernel::EventQueue::KernelDeleteEvent( eq, static_cast(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS); + if (result == OK || result == LibKernel::KERNEL_ERROR_ENOENT) { + renderer.DeleteInterruptEq(eq, id); + } return result; } diff --git a/src/graphics/host_gpu/renderer/sync.h b/src/graphics/host_gpu/renderer/sync.h index 7abf1d67f..cec6677ca 100644 --- a/src/graphics/host_gpu/renderer/sync.h +++ b/src/graphics/host_gpu/renderer/sync.h @@ -17,8 +17,7 @@ namespace Sync { uint64_t& value); [[nodiscard]] uint64_t ReadReferenceClock(); -void TriggerAgcUserInterrupt(); -void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, uint32_t context_id); +void TriggerEopEventAtEndOfPipe(CommandBuffer& buffer, int event_id, uint32_t context_id); void WriteAtEndOfPipe32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value); @@ -35,16 +34,16 @@ void WriteAtEndOfPipeWithWriteBack32(uint64_t submit_id, CommandBuffer& buffer, void WriteAtEndOfPipeWithWriteBack64(uint64_t submit_id, CommandBuffer& buffer, uint64_t* dst_gpu_addr, uint64_t value); void WriteAtEndOfPipeWithInterrupt32(uint64_t submit_id, CommandBuffer& buffer, - uint32_t* dst_gpu_addr, uint32_t value, + uint32_t* dst_gpu_addr, uint32_t value, int event_id, uint32_t context_id = 0); void WriteAtEndOfPipeWithInterrupt64(uint64_t submit_id, CommandBuffer& buffer, - uint64_t* dst_gpu_addr, uint64_t value, + uint64_t* dst_gpu_addr, uint64_t value, int event_id, uint32_t context_id = 0); void WriteAtEndOfPipeWithInterruptWriteBack32(uint64_t submit_id, CommandBuffer& buffer, - uint32_t* dst_gpu_addr, uint32_t value, + uint32_t* dst_gpu_addr, uint32_t value, int event_id, uint32_t context_id = 0); void WriteAtEndOfPipeWithInterruptWriteBack64(uint64_t submit_id, CommandBuffer& buffer, - uint64_t* dst_gpu_addr, uint64_t value, + uint64_t* dst_gpu_addr, uint64_t value, int event_id, uint32_t context_id = 0); [[nodiscard]] uint64_t PrepareVideoOutFlip(CommandBuffer& buffer, int handle, int index, @@ -57,11 +56,12 @@ void WriteAtEndOfPipeWithFlip32(uint64_t submit_id, CommandBuffer& buffer, uint3 void WriteAtEndOfPipeWithInterruptWriteBackFlip32(uint64_t submit_id, CommandBuffer& buffer, uint32_t* dst_gpu_addr, uint32_t value, int handle, int index, int flip_mode, - int64_t flip_arg, uint64_t request_id); + int64_t flip_arg, uint64_t request_id, + int event_id); int AddEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id, void* udata); -int DeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, int id); +int DeleteEqEvent(RenderContext& renderer, LibKernel::EventQueue::KernelEqueue eq, int id); void ReadGds(const Buffer& gds, uint32_t* dst, uint32_t dw_offset, uint32_t dw_size); } // namespace Sync diff --git a/src/libs/agc.cpp b/src/libs/agc.cpp index a72904706..ebf6a73da 100644 --- a/src/libs/agc.cpp +++ b/src/libs/agc.cpp @@ -67,7 +67,7 @@ void Shutdown() { g_renderer = nullptr; } -void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer) { +void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, const uint32_t* cmd_buffer) { EXIT_IF(type == nullptr); static std::atomic_int id = 0; @@ -4228,37 +4228,10 @@ struct TessellationDriverState { static TessellationDriverState g_tessellation_driver_state {}; -static bool dcb_has_queued_interrupt(const uint32_t* dcb, uint32_t size_in_dwords) { - if (dcb == nullptr) { - return false; - } - - for (uint32_t offset = 0; offset < size_in_dwords;) { - auto cmd_id = dcb[offset]; - auto len = KYTY_PM4_LEN(cmd_id); - if (len == 0 || len > size_in_dwords - offset) { - return false; - } - - auto op = (cmd_id >> 8u) & 0xffu; - if (op == Pm4::IT_NOP && KYTY_PM4_R(cmd_id) == Pm4::R_RELEASE_MEM && len >= 6) { - auto interrupt = (dcb[offset + 2] >> 24u) & 0x7u; - if (interrupt == 1 || interrupt == 2 || interrupt >= 4) { - return true; - } - } - - offset += len; - } - - return false; -} - 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(dcb, size_in_dwords, nullptr, 0, - !dcb_has_queued_interrupt(dcb, size_in_dwords)); + g_renderer->GetGpu().Submit(std::span {dcb, size_in_dwords}, {}); } int KYTY_SYSV_ABI AgcDriverSubmitDcb(const Packet* packet) { @@ -4333,9 +4306,8 @@ static void submit_acb(uint32_t queue, uint32_t* acb, uint32_t size_in_dwords) { GraphicsDbgDumpDcb("a", size_in_dwords, acb); - const bool trigger_interrupt_on_done = !dcb_has_queued_interrupt(acb, size_in_dwords); EXIT_IF(g_renderer == nullptr); - g_renderer->GetGpu().SubmitCompute(queue, acb, size_in_dwords, trigger_interrupt_on_done); + g_renderer->GetGpu().SubmitCompute(queue, std::span {acb, size_in_dwords}); } static uint32_t get_driver_queue(const void* queue_context) { @@ -4461,7 +4433,8 @@ int KYTY_SYSV_ABI AgcDriverDeleteEqEvent(LibKernel::EventQueue::KernelEqueue eq, return LibKernel::KERNEL_ERROR_EBADF; } - return Sync::DeleteEqEvent(eq, id); + EXIT_IF(g_renderer == nullptr); + return Sync::DeleteEqEvent(*g_renderer, eq, id); } int KYTY_SYSV_ABI AgcDriverGetEqEventType(const LibKernel::EventQueue::KernelEvent* ev) { diff --git a/src/libs/agc.h b/src/libs/agc.h index 75017d193..a8dd490bd 100644 --- a/src/libs/agc.h +++ b/src/libs/agc.h @@ -29,7 +29,7 @@ struct Lifecycle { static constexpr auto shutdown = Libs::Graphics::Shutdown; }; -void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, uint32_t* cmd_buffer); +void GraphicsDbgDumpDcb(const char* type, uint32_t num_dw, const uint32_t* cmd_buffer); namespace Gen5 { diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index 407385ac7..a17754da4 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -42,8 +42,10 @@ #include "graphics/shader/recompiler/ir/passes/BindingLayout.h" #include "graphics/shader/rectListShader.h" #include "graphics/shader/shader.h" +#include "kernel/eventQueue.h" #include "kernel/memory.h" #include "libs/agc.h" +#include "libs/errno.h" #include "spirv-tools/libspirv.hpp" #if __has_include("graphics/host_gpu/renderer/renderTargetBarriers.h") @@ -2051,7 +2053,7 @@ public: constexpr uint64_t release_tick = 1; auto &gpu_scheduler = context.GetCommandScheduler(); - auto processor = std::make_unique(context); + auto processor = std::make_unique(context, 0); gpu.SendCommandSync([&] { processor->BufferInit(); SubmitInfo blocked_submit; @@ -2070,8 +2072,7 @@ public: processor->TriggerEvent(0x16u, 0u); auto packet = make_release_mem(0, 0, nullptr, 0); Pm4Execution execution; - const auto result = - processor->Process(execution, packet.data(), packet.size()); + const auto result = processor->Process(execution, packet); processor->IncrementDe(); const bool cache_and_counter_did_not_submit = result == Pm4ProcessResult::Complete && @@ -2081,8 +2082,8 @@ public: auto cb_db_release = make_release_mem(2, 0, &cb_db_release_label, 0, 0x14u, 0); Pm4Execution cb_db_execution; - const auto cb_db_result = processor->Process( - cb_db_execution, cb_db_release.data(), cb_db_release.size()); + const auto cb_db_result = + processor->Process(cb_db_execution, cb_db_release); const bool cb_db_release_did_not_submit = cb_db_result == Pm4ProcessResult::Complete && cb_db_release_label == 0 && @@ -2092,9 +2093,8 @@ public: make_release_mem(5, 1, &interrupt_only_gds_label, 1ull << 16u); Pm4Execution gds_interrupt_execution; const auto interrupt_tick = gpu_scheduler.CurrentTick(); - const auto interrupt_result = processor->Process( - gds_interrupt_execution, gds_interrupt_only.data(), - gds_interrupt_only.size()); + const auto interrupt_result = + processor->Process(gds_interrupt_execution, gds_interrupt_only); parser_kept_nonblocking_boundaries = cache_and_counter_did_not_submit && cb_db_release_did_not_submit && @@ -2133,24 +2133,23 @@ public: auto immediate = make_release_mem(1, 0, &release_label, 0x11223344u); Pm4Execution immediate_execution; const auto immediate_tick = gpu_scheduler.CurrentTick(); - const auto immediate_result = processor->Process( - immediate_execution, immediate.data(), immediate.size()); + const auto immediate_result = + processor->Process(immediate_execution, immediate); const bool immediate_split_once = gpu_scheduler.CurrentTick() == immediate_tick + 1; auto gds = make_release_mem(5, 0, &gds_label, 1ull << 16u); Pm4Execution gds_execution; const auto gds_tick = gpu_scheduler.CurrentTick(); - const auto gds_result = - processor->Process(gds_execution, gds.data(), gds.size()); + const auto gds_result = processor->Process(gds_execution, gds); const bool gds_waited_once = gpu_scheduler.CurrentTick() == gds_tick + 1; auto interrupt_only = make_release_mem(0, 4, nullptr, 0); Pm4Execution interrupt_execution; const auto interrupt_tick = gpu_scheduler.CurrentTick(); - const auto interrupt_result = processor->Process( - interrupt_execution, interrupt_only.data(), interrupt_only.size()); + const auto interrupt_result = + processor->Process(interrupt_execution, interrupt_only); const bool interrupt_split_once = gpu_scheduler.CurrentTick() == interrupt_tick + 1; @@ -2158,8 +2157,7 @@ public: Pm4Execution gds_interrupt_execution; const auto gds_interrupt_tick = gpu_scheduler.CurrentTick(); const auto gds_interrupt_result = - processor->Process(gds_interrupt_execution, gds_interrupt.data(), - gds_interrupt.size()); + processor->Process(gds_interrupt_execution, gds_interrupt); const bool gds_interrupt_waited_once = gpu_scheduler.CurrentTick() == gds_interrupt_tick + 1; @@ -2191,6 +2189,200 @@ public: packet[3] = static_cast(destination_address >> 32u); packet[4] = value; }; + + uint32_t live_graphics_value = 0; + std::array live_graphics_commands{}; + write_packet(live_graphics_commands.data(), &live_graphics_value, 11); + std::binary_semaphore graphics_gate_entered{0}; + std::binary_semaphore graphics_gate_release{0}; + gpu.SendCommand([&] { + graphics_gate_entered.release(); + graphics_gate_release.acquire(); + }); + gpu.Submit(live_graphics_commands, {}); + graphics_gate_entered.acquire(); + live_graphics_commands[4] = 22; + graphics_gate_release.release(); + gpu.Done(); + Require("GpuCommandLane", "borrowed graphics commands", + live_graphics_value == 22, + "graphics submission executed a copied PM4 stream"); + + uint32_t live_compute_value = 0; + std::array live_compute_commands{}; + write_packet(live_compute_commands.data(), &live_compute_value, 33); + std::binary_semaphore compute_gate_entered{0}; + std::binary_semaphore compute_gate_release{0}; + gpu.SendCommand([&] { + compute_gate_entered.release(); + compute_gate_release.acquire(); + }); + gpu.SubmitCompute(0x20, live_compute_commands); + compute_gate_entered.acquire(); + live_compute_commands[4] = 44; + compute_gate_release.release(); + gpu.Done(); + Require("GpuCommandLane", "borrowed compute commands", + live_compute_value == 44, + "compute submission executed a copied PM4 stream"); + + LibKernel::EventQueue::KernelEqueue interrupt_queue = + LibKernel::EventQueue::KERNEL_EQUEUE_INVALID; + uint32_t graphics_interrupt_udata = 0; + uint32_t compute_interrupt_udata = 0; + uint32_t other_compute_interrupt_udata = 0; + const bool interrupt_queue_ready = + LibKernel::EventQueue::KernelCreateEqueue(&interrupt_queue, + "pm4-interrupts") == 0 && + Sync::AddEqEvent(context, interrupt_queue, 0, + &graphics_interrupt_udata) == 0 && + Sync::AddEqEvent(context, interrupt_queue, 0x20, + &compute_interrupt_udata) == 0 && + Sync::AddEqEvent(context, interrupt_queue, 0x21, + &other_compute_interrupt_udata) == 0; + Require("GpuCommandLane", "interrupt queue", interrupt_queue_ready, + "failed to register the PM4 interrupt events"); + + const auto make_interrupt_packet = + [](uint32_t data_selector, uint32_t interrupt_selector, + void *destination, uint64_t value, uint32_t context_id) { + std::array packet{}; + const auto address = reinterpret_cast(destination); + packet[0] = KYTY_PM4(8, Pm4::IT_NOP, Pm4::R_RELEASE_MEM); + packet[1] = 0x28u | (5u << 8u); + packet[2] = (interrupt_selector << 24u) | (data_selector << 29u); + packet[3] = static_cast(address); + packet[4] = static_cast(address >> 32u); + packet[5] = static_cast(value); + packet[6] = static_cast(value >> 32u); + packet[7] = context_id & 0x07ffffffu; + return packet; + }; + const auto finish_gpu = [&] { + gpu.SendCommandSync([&] { context.GetCommandScheduler().Finish(); }); + }; + const auto wait_for_interrupt = + [&](LibKernel::EventQueue::KernelEvent &event, int &count) { + LibKernel::KernelUseconds timeout = 0; + return LibKernel::EventQueue::KernelWaitEqueue( + interrupt_queue, &event, 1, &count, &timeout); + }; + + uint32_t no_interrupt_graphics_value = 0; + 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.Done(); + finish_gpu(); + + LibKernel::EventQueue::KernelEvent interrupt_event{}; + int interrupt_count = 0; + const auto no_graphics_interrupt_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + Require("GpuCommandLane", "no implicit graphics interrupt", + no_graphics_interrupt_wait == LibKernel::KERNEL_ERROR_ETIMEDOUT && + interrupt_count == 0 && no_interrupt_graphics_value == 55, + "graphics submission completion synthesized an interrupt"); + + auto live_interrupt_commands = + make_interrupt_packet(0, 1, nullptr, 0, 0x234u); + std::binary_semaphore interrupt_gate_entered{0}; + std::binary_semaphore interrupt_gate_release{0}; + gpu.SendCommand([&] { + interrupt_gate_entered.release(); + interrupt_gate_release.acquire(); + }); + gpu.SubmitCompute(0x20, live_interrupt_commands); + interrupt_gate_entered.acquire(); + live_interrupt_commands[2] = 0; + interrupt_gate_release.release(); + gpu.Done(); + finish_gpu(); + + interrupt_count = 0; + const auto no_interrupt_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + Require("GpuCommandLane", "no implicit completion interrupt", + no_interrupt_wait == LibKernel::KERNEL_ERROR_ETIMEDOUT && + interrupt_count == 0, + "submission completion synthesized an interrupt absent from the " + "executed PM4 stream"); + + 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.Done(); + finish_gpu(); + + interrupt_count = 0; + const auto graphics_interrupt_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + Require("GpuCommandLane", "graphics interrupt routing", + graphics_interrupt_wait == 0 && interrupt_count == 1 && + interrupt_event.ident == 0 && interrupt_event.data == 0 && + interrupt_event.udata == &graphics_interrupt_udata && + graphics_interrupt_label == 0xa5a5a5a5u, + "graphics kOnly interrupt was misrouted or wrote its label"); + + uint32_t compute_interrupt_label = 0x5a5a5a5au; + auto compute_interrupt_commands = make_interrupt_packet( + 1, 0, &compute_interrupt_label, 0x55667788u, 0x456u); + std::binary_semaphore compute_interrupt_gate_entered{0}; + std::binary_semaphore compute_interrupt_gate_release{0}; + gpu.SendCommand([&] { + compute_interrupt_gate_entered.release(); + compute_interrupt_gate_release.acquire(); + }); + gpu.SubmitCompute(0x20, compute_interrupt_commands); + compute_interrupt_gate_entered.acquire(); + compute_interrupt_commands[2] |= 1u << 24u; + compute_interrupt_gate_release.release(); + gpu.Done(); + finish_gpu(); + + interrupt_count = 0; + const auto compute_interrupt_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + const bool compute_interrupt_matches = + compute_interrupt_wait == 0 && interrupt_count == 1 && + interrupt_event.ident == 0x20 && interrupt_event.data == 0x456u && + interrupt_event.udata == &compute_interrupt_udata && + compute_interrupt_label == 0x55667788u; + + uint64_t compute_clock_label = 0; + auto compute_clock_commands = make_interrupt_packet( + 3, 1, &compute_clock_label, 0, 0x567u); + gpu.SubmitCompute(0x20, compute_clock_commands); + gpu.Done(); + finish_gpu(); + + interrupt_count = 0; + const auto compute_clock_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + const bool compute_clock_matches = + compute_clock_wait == 0 && interrupt_count == 1 && + interrupt_event.ident == 0x20 && interrupt_event.data == 0x567u && + interrupt_event.udata == &compute_interrupt_udata && + compute_clock_label != 0; + + interrupt_count = 0; + const auto extra_interrupt_wait = + wait_for_interrupt(interrupt_event, interrupt_count); + const auto delete_other_compute_event = + Sync::DeleteEqEvent(context, interrupt_queue, 0x21); + LibKernel::EventQueue::KernelDeleteEqueue(interrupt_queue); + context.TriggerInterrupt(0, 0); + context.TriggerInterrupt(0x20, 0); + context.TriggerInterrupt(0x21, 0); + Require("GpuCommandLane", "compute interrupt routing", + compute_interrupt_matches && compute_clock_matches && + extra_interrupt_wait == LibKernel::KERNEL_ERROR_ETIMEDOUT && + interrupt_count == 0 && delete_other_compute_event == 0, + "compute kOnly interrupt was misrouted, broadcast, or lost a " + "label write"); + std::array polling_loop{}; for (size_t i = 0; i < polling_loop.size() - 4; i += 2) { polling_loop[i] = KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_ZERO); @@ -2217,7 +2409,7 @@ public: stream_gate_entered.release(); stream_gate_release.acquire(); }); - gpu.Submit(polling_commands.data(), polling_commands.size(), nullptr, 0); + gpu.Submit(polling_commands, {}); stream_gate_entered.acquire(); stream_gate_release.release(); uint32_t packet_marker_a_at_callback = UINT32_MAX; @@ -2228,6 +2420,7 @@ public: if (packet_marker_a == 11 && packet_marker_b == 0) { packet_marker_a_at_callback = packet_marker_a; packet_marker_b_at_callback = packet_marker_b; + polling_commands[13] = 33; polling_loop[1020] = KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_ZERO); polling_loop[1021] = 0; polling_loop[1022] = KYTY_PM4(2, Pm4::IT_NOP, Pm4::R_ZERO); @@ -2240,8 +2433,9 @@ public: Require("GpuCommandLane", "packet-boundary command polling", packet_marker_a_at_callback == 11 && packet_marker_b_at_callback == 0 && packet_marker_a == 11 && - packet_marker_b == 22, - "host command waited for an entire non-suspended PM4 stream"); + packet_marker_b == 33, + "host command waited for an entire PM4 stream or resumed a copied " + "stream"); uint32_t label = 0; uint32_t prefix = 0; @@ -2266,8 +2460,7 @@ public: commands[14] = static_cast(address(&suffix)); commands[15] = static_cast(address(&suffix) >> 32u); commands[16] = 22; - gpu.Submit(commands.data(), static_cast(commands.size()), nullptr, - 0); + gpu.Submit(commands, {}); std::binary_semaphore ordered_started{0}; std::atomic ordered_finished{false}; @@ -2297,8 +2490,7 @@ public: label = 0; prefix = 0; suffix = 0; - gpu.Submit(commands.data(), static_cast(commands.size()), nullptr, - 0); + gpu.Submit(commands, {}); std::binary_semaphore unmap_complete{0}; std::jthread unmap_thread([&] { @@ -2438,8 +2630,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.data(), static_cast(dma_commands.size()), - nullptr, 0); + gpu.Submit(dma_commands, {}); gpu.Done(); constexpr uint32_t clean_fill_value = 0xdecafbad; gpu.SendCommandSync([&] { @@ -23118,7 +23309,7 @@ void CheckVulkan13FeatureRequirements() { void CheckPm4AcquireMemNoOp(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); const std::array standard_payload{0x00400000u, 1u, 0u, 0u, 0u, 10u}; const std::array custom_payload{ @@ -23141,7 +23332,7 @@ void CheckPm4AcquireMemNoOp(RenderContext &renderer) { void CheckPm4SyntheticOcclusionCounterDump(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); constexpr uint64_t untouched = 0x1122334455667788ull; constexpr uint64_t ready_bit = 1ull << 63u; alignas(16) std::array, 16> results; @@ -23156,7 +23347,7 @@ void CheckPm4SyntheticOcclusionCounterDump(RenderContext &renderer) { static_cast(raw_address), static_cast(raw_address >> 32u)}; Pm4Execution execution; - return processor.Process(execution, packet.data(), packet.size()); + return processor.Process(execution, packet); }; const auto begin_result = dump(&results[0][0]); @@ -23181,7 +23372,7 @@ void CheckPm4SyntheticOcclusionCounterDump(RenderContext &renderer) { } void CheckPm4StencilInfoValueLane(RenderContext &renderer) { - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); constexpr std::array payload{0x00100801u, 0x28000000u}; const auto consumed = HwCtxSetStencilInfo( processor, 0xC0016900u, Pm4::DB_STENCIL_INFO, payload.data(), 1); @@ -23197,7 +23388,7 @@ void CheckPm4StencilInfoValueLane(RenderContext &renderer) { void CheckPm4DirectShaderRegisterFallback(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); constexpr uint64_t shader_address = 0x0000123456789a00ull; std::array packet{ KYTY_PM4(4, Pm4::IT_SET_SH_REG, Pm4::R_ZERO), @@ -23207,8 +23398,7 @@ void CheckPm4DirectShaderRegisterFallback(RenderContext &renderer) { }; Pm4Execution execution; Require("Pm4DirectShaderRegisterFallback", "ES program base", - processor.Process(execution, packet.data(), packet.size()) == - Pm4ProcessResult::Complete && + processor.Process(execution, packet) == Pm4ProcessResult::Complete && processor.GetShCtx().GetVs().es_regs.data_addr == shader_address, "direct SET_SH_REG did not route its ES base pair through the " "register handlers"); @@ -23217,7 +23407,7 @@ void CheckPm4DirectShaderRegisterFallback(RenderContext &renderer) { void CheckPm4GuardBandRegisterRanges(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); processor.GetCtx().SetGuardBands(2.0f, 3.0f, 4.0f, 5.0f); std::array single{ @@ -23226,8 +23416,7 @@ void CheckPm4GuardBandRegisterRanges(RenderContext &renderer) { std::bit_cast(6.0f), }; Pm4Execution single_execution; - const auto single_result = - processor.Process(single_execution, single.data(), single.size()); + const auto single_result = processor.Process(single_execution, single); const auto &single_viewport = processor.GetCtx().GetScreenViewport(); Require("Pm4GuardBandRegisterRanges", "single register", single_result == Pm4ProcessResult::Complete && @@ -23246,8 +23435,7 @@ void CheckPm4GuardBandRegisterRanges(RenderContext &renderer) { std::bit_cast(10.0f), }; Pm4Execution range_execution; - const auto range_result = - processor.Process(range_execution, range.data(), range.size()); + const auto range_result = processor.Process(range_execution, range); const auto &range_viewport = processor.GetCtx().GetScreenViewport(); Require("Pm4GuardBandRegisterRanges", "full range", range_result == Pm4ProcessResult::Complete && @@ -23261,7 +23449,7 @@ void CheckPm4GuardBandRegisterRanges(RenderContext &renderer) { void CheckPm4BlendColorRegisterRanges(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); processor.GetCtx().SetBlendColor({1.0f, 2.0f, 3.0f, 4.0f}); constexpr std::array, 4> singleton_values{{ @@ -23279,8 +23467,7 @@ void CheckPm4BlendColorRegisterRanges(RenderContext &renderer) { }; Pm4Execution execution; singletons_complete &= - processor.Process(execution, packet.data(), packet.size()) == - Pm4ProcessResult::Complete; + processor.Process(execution, packet) == Pm4ProcessResult::Complete; } const auto &singletons = processor.GetCtx().GetBlendColor(); Require("Pm4BlendColorRegisterRanges", "single registers", @@ -23296,8 +23483,7 @@ void CheckPm4BlendColorRegisterRanges(RenderContext &renderer) { std::bit_cast(10.0f), }; Pm4Execution partial_execution; - const auto partial_result = - processor.Process(partial_execution, partial.data(), partial.size()); + const auto partial_result = processor.Process(partial_execution, partial); const auto &partial_color = processor.GetCtx().GetBlendColor(); Require("Pm4BlendColorRegisterRanges", "partial range", partial_result == Pm4ProcessResult::Complete && @@ -23314,8 +23500,7 @@ void CheckPm4BlendColorRegisterRanges(RenderContext &renderer) { std::bit_cast(14.0f), }; Pm4Execution full_execution; - const auto full_result = - processor.Process(full_execution, full.data(), full.size()); + const auto full_result = processor.Process(full_execution, full); const auto &full_color = processor.GetCtx().GetBlendColor(); Require("Pm4BlendColorRegisterRanges", "full range", full_result == Pm4ProcessResult::Complete && @@ -23327,7 +23512,7 @@ void CheckPm4BlendColorRegisterRanges(RenderContext &renderer) { void CheckPm4PolygonOffsetRegisters(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); const auto &defaults = processor.GetCtx().GetPolyOffset(); Require("Pm4PolygonOffset", "format defaults", defaults.neg_num_db_bits == -23 && defaults.db_is_float_fmt, @@ -23380,11 +23565,11 @@ static_assert(offsetof(AgcCommandBufferLayout, reserved_dw) == 0x30); void CheckAgcWaitPackets(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); constexpr auto packet_mismatch = static_cast(0x8a6c000cu); const auto execute = [&](uint32_t *packet, uint32_t size_dw) { Pm4Execution execution; - return processor.Process(execution, packet, size_dw) == + return processor.Process(execution, {packet, size_dw}) == Pm4ProcessResult::Complete; }; @@ -23515,10 +23700,10 @@ void CheckAgcWaitPackets(RenderContext &renderer) { void CheckAgcDrawIndirectMultiPacket(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); const auto execute = [&](uint32_t *packet, uint32_t size_dw) { Pm4Execution execution; - return processor.Process(execution, packet, size_dw) == + return processor.Process(execution, {packet, size_dw}) == Pm4ProcessResult::Complete; }; @@ -23561,7 +23746,7 @@ void CheckAgcDrawIndirectMultiPacket(RenderContext &renderer) { void CheckPm4ContextStateOperations(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); constexpr auto primitive_type = static_cast(0x35u); HW::RenderControl original_control{}; @@ -23626,7 +23811,7 @@ void CheckPm4ContextStateOperations(RenderContext &renderer) { segment_offset == size_dw && packet_matches, "context-state HLE packet does not match its real allocation size"); Pm4Execution execution; - return processor.Process(execution, packet.data(), size_dw); + return processor.Process(execution, {packet.data(), size_dw}); }; Require("Pm4ContextState", "push-clear", @@ -23675,8 +23860,7 @@ void CheckPm4ContextStateOperations(RenderContext &renderer) { std::array clear_state_packet{0xc0001200, 0}; Pm4Execution clear_state_execution; Require("Pm4ContextState", "clear-state packet", - processor.Process(clear_state_execution, clear_state_packet.data(), - clear_state_packet.size()) == + processor.Process(clear_state_execution, clear_state_packet) == Pm4ProcessResult::Complete && processor.GetCtx().GetRenderTargetMask() == HW::Context{}.GetRenderTargetMask(), @@ -23711,7 +23895,7 @@ void CheckPm4ContextStateOperations(RenderContext &renderer) { void CheckPm4WaitResume(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); uint32_t label = 0; uint32_t prefix = 0; @@ -23758,8 +23942,7 @@ void CheckPm4WaitResume(RenderContext &renderer) { Pm4Execution execution; Require("Pm4WaitResume", "suspend", - processor.Process(execution, commands.data(), commands.size()) == - Pm4ProcessResult::Blocked && + processor.Process(execution, commands) == Pm4ProcessResult::Blocked && prefix == 11 && child_observation == 0 && suffix == 0, "blocked indirect wait did not preserve its command position"); @@ -23767,8 +23950,7 @@ void CheckPm4WaitResume(RenderContext &renderer) { child[4] = 1; Require( "Pm4WaitResume", "resume", - processor.Process(execution, commands.data(), commands.size()) == - Pm4ProcessResult::Complete && + processor.Process(execution, commands) == Pm4ProcessResult::Complete && prefix == 11 && child_observation == 0 && suffix == 22, "resumed indirect wait replayed a child or did not finish its parent"); std::printf("[host] %-32s ok\n", "Pm4WaitResume"); @@ -23776,7 +23958,7 @@ void CheckPm4WaitResume(RenderContext &renderer) { void CheckPm4RewindResume(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); uint32_t suffix = 0; const auto address = reinterpret_cast(&suffix); @@ -23791,8 +23973,7 @@ void CheckPm4RewindResume(RenderContext &renderer) { Pm4Execution execution; Require("Pm4RewindResume", "pending", - processor.Process(execution, commands.data(), commands.size()) == - Pm4ProcessResult::Blocked && + processor.Process(execution, commands) == Pm4ProcessResult::Blocked && suffix == 0, "pending rewind did not preserve its command position"); Require("Pm4RewindResume", "patch valid", @@ -23800,7 +23981,7 @@ void CheckPm4RewindResume(RenderContext &renderer) { commands[1] == 0x80000000u, "rewind state patch did not set the valid bit"); Require("Pm4RewindResume", "resume", - processor.Process(execution, commands.data(), commands.size()) == + processor.Process(execution, commands) == Pm4ProcessResult::Complete && suffix == 33, "valid rewind did not resume at the following packet"); @@ -23809,7 +23990,7 @@ void CheckPm4RewindResume(RenderContext &renderer) { void CheckPm4CeCompletion(RenderContext &renderer) { GraphicsInitJmpTables(); - CommandProcessor processor(renderer); + CommandProcessor processor(renderer, 0); uint32_t suffix = 0; const auto address = reinterpret_cast(&suffix); @@ -23827,35 +24008,33 @@ void CheckPm4CeCompletion(RenderContext &renderer) { processor.ResetDeCe(); Pm4Execution execution; Require("Pm4CeCompletion", "wait", - processor.Process(execution, commands.data(), commands.size()) == - Pm4ProcessResult::Blocked && + 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.data(), - ce_increment.size()) == Pm4ProcessResult::Complete, + processor.Process(ce_execution, ce_increment) == + Pm4ProcessResult::Complete, "CE counter increment did not complete"); Require( "Pm4CeCompletion", "counter gate", - processor.Process(execution, commands.data(), commands.size()) == - Pm4ProcessResult::Complete && + 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.data(), - commands.size()) == Pm4ProcessResult::Blocked && + 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.data(), - commands.size()) == Pm4ProcessResult::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");