mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
graphics: do not copy PM4 streams & route executed packet interrupts properly
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
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<const uint32_t> commands;
|
||||
uint32_t offset_dw = 0;
|
||||
uint32_t deferred_advance_dw = 0;
|
||||
};
|
||||
|
||||
std::vector<BufferCursor> 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<const uint32_t> commands);
|
||||
void ProcessIndirectBuffer(std::span<const uint32_t> 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 <typename T>
|
||||
@@ -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
|
||||
|
||||
@@ -1859,11 +1859,11 @@ KYTY_CP_OP_PARSER(CpOpBranch) {
|
||||
uint64_t reference = buffer[5] | (static_cast<uint64_t>(buffer[6]) << 32u);
|
||||
uint32_t mode = buffer[0] & 0x3u;
|
||||
uint32_t function = (buffer[0] >> 8u) & 0x7u;
|
||||
auto* then_buffer = reinterpret_cast<uint32_t*>((buffer[7] & 0xfffffffcu) |
|
||||
(static_cast<uint64_t>(buffer[8]) << 32u));
|
||||
auto* then_buffer = reinterpret_cast<const uint32_t*>(
|
||||
(buffer[7] & 0xfffffffcu) | (static_cast<uint64_t>(buffer[8]) << 32u));
|
||||
uint32_t then_num_dw = buffer[9] & 0xfffffu;
|
||||
auto* else_buffer = reinterpret_cast<uint32_t*>((buffer[10] & 0xfffffffcu) |
|
||||
(static_cast<uint64_t>(buffer[11]) << 32u));
|
||||
auto* else_buffer = reinterpret_cast<const uint32_t*>(
|
||||
(buffer[10] & 0xfffffffcu) | (static_cast<uint64_t>(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<uint64_t>(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<uint32_t*>(buffer[0] | (static_cast<uint64_t>(buffer[1]) << 32u));
|
||||
reinterpret_cast<const uint32_t*>(buffer[0] | (static_cast<uint64_t>(buffer[1]) << 32u));
|
||||
uint32_t indirect_num_dw = control & 0xfffffu;
|
||||
static std::atomic<uint32_t> 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;
|
||||
}
|
||||
|
||||
@@ -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<CommandProcessor>(renderer);
|
||||
m_gfx_cp = std::make_unique<CommandProcessor>(renderer, 0);
|
||||
m_thread = std::jthread(ThreadRun, this);
|
||||
}
|
||||
|
||||
@@ -148,39 +141,33 @@ void GuestGpu::SendCommandSync(Common::UniqueFunction<void>&& 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<const uint32_t> draw_commands,
|
||||
std::span<const uint32_t> 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<const uint32_t> 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<CommandProcessor>(m_renderer);
|
||||
processor = std::make_unique<CommandProcessor>(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<uint32_t>(submission.commands.size());
|
||||
const auto* buffer = submission.commands.data();
|
||||
static uint32_t compute_batch_log_count = 0;
|
||||
if (first_slice && num_dw <= 128 && compute_batch_log_count++ < 32) {
|
||||
LOGF("compute direct batch: data=0x%016" PRIx64 ", num_dw=%" PRIu32 "\n",
|
||||
@@ -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<const uint32_t> 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<const uint32_t> 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<uint32_t>(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<uint64_t*>(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<uint64_t*>(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<uint64_t*>(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<uint32_t*>(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();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
@@ -31,12 +31,12 @@ public:
|
||||
void SendCommand(Common::UniqueFunction<void>&& command);
|
||||
void SendCommandSync(Common::UniqueFunction<void>&& 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<const uint32_t> draw_commands,
|
||||
std::span<const uint32_t> constant_commands);
|
||||
void SubmitCompute(uint32_t queue, std::span<const uint32_t> 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<uint32_t>(m_words.size());
|
||||
}
|
||||
[[nodiscard]] uint32_t* Data() noexcept { return m_words.data(); }
|
||||
|
||||
private:
|
||||
std::vector<uint32_t> 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<const uint32_t> commands;
|
||||
std::span<const uint32_t> 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);
|
||||
|
||||
@@ -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<uint32_t*>((static_cast<uint64_t>(cmd[0]) & 0xfffffffcu) |
|
||||
(static_cast<uint64_t>(cmd[1]) << 32u));
|
||||
auto* indirect_buffer = reinterpret_cast<const uint32_t*>(
|
||||
(static_cast<uint64_t>(cmd[0]) & 0xfffffffcu) |
|
||||
(static_cast<uint64_t>(cmd[1]) << 32u));
|
||||
const uint32_t indirect_num_regs = cmd[3] & 0x3fffu;
|
||||
|
||||
for (uint32_t i = 0; indirect_buffer != nullptr && i < indirect_num_regs;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <algorithm>
|
||||
@@ -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<EopEqRegistration> registrations;
|
||||
void RenderContext::TriggerInterrupt(int event_id, uint32_t context_id) {
|
||||
std::vector<InterruptEqRegistration> 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<uintptr_t>(registration.id),
|
||||
registration.eq, static_cast<uintptr_t>(registration.event_id),
|
||||
LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(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<void*>(tsc));
|
||||
EXIT_NOT_IMPLEMENTED(result != OK && result != LibKernel::KERNEL_ERROR_ENOENT);
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -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<GuestGpu> m_gpu;
|
||||
VideoOut::VideoOutDriver* m_video_out = nullptr;
|
||||
|
||||
Common::Mutex m_eop_mutex;
|
||||
std::vector<EopEqRegistration> m_eop_eqs;
|
||||
Common::Mutex m_interrupt_mutex;
|
||||
std::vector<InterruptEqRegistration> m_interrupt_eqs;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -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<uint32_t, 4> debug_args = {};
|
||||
uint64_t debug_data = 0;
|
||||
std::optional<uint64_t> 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<uint32_t>(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<uint32_t>(size);
|
||||
const auto value_low = static_cast<uint32_t>(value);
|
||||
const auto value_high = static_cast<uint32_t>(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<void*>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(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<uint64_t>(dst_gpu_addr);
|
||||
RecordEndOfPipeSignal({
|
||||
.buffer = &buffer,
|
||||
.submit_id = submit_id,
|
||||
.debug_operation = CommandBufferDebugOp::EopWriteBackFlip,
|
||||
.debug_args = {static_cast<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value},
|
||||
.debug_data = static_cast<uint64_t>(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<uint32_t>(handle), static_cast<uint32_t>(index),
|
||||
static_cast<uint32_t>(flip_mode), value},
|
||||
.debug_data = static_cast<uint64_t>(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<RenderContext*>(event->filter.data);
|
||||
EXIT_IF(renderer == nullptr);
|
||||
renderer->DeleteEopEq(eq, static_cast<int>(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<uintptr_t>(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<uintptr_t>(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<uintptr_t>(id), LibKernel::EventQueue::KERNEL_EVFILT_GRAPHICS);
|
||||
if (result == OK || result == LibKernel::KERNEL_ERROR_ENOENT) {
|
||||
renderer.DeleteInterruptEq(eq, id);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+5
-32
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
|
||||
@@ -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<CommandProcessor>(context);
|
||||
auto processor = std::make_unique<CommandProcessor>(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<uint32_t>(destination_address >> 32u);
|
||||
packet[4] = value;
|
||||
};
|
||||
|
||||
uint32_t live_graphics_value = 0;
|
||||
std::array<uint32_t, 5> 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<uint32_t, 5> 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<uint32_t, 8> packet{};
|
||||
const auto address = reinterpret_cast<uint64_t>(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<uint32_t>(address);
|
||||
packet[4] = static_cast<uint32_t>(address >> 32u);
|
||||
packet[5] = static_cast<uint32_t>(value);
|
||||
packet[6] = static_cast<uint32_t>(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<uint32_t, 5> no_interrupt_graphics_commands{};
|
||||
write_packet(no_interrupt_graphics_commands.data(),
|
||||
&no_interrupt_graphics_value, 55);
|
||||
gpu.Submit(no_interrupt_graphics_commands, {});
|
||||
gpu.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<uint32_t, 1024> 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<uint32_t>(address(&suffix));
|
||||
commands[15] = static_cast<uint32_t>(address(&suffix) >> 32u);
|
||||
commands[16] = 22;
|
||||
gpu.Submit(commands.data(), static_cast<uint32_t>(commands.size()), nullptr,
|
||||
0);
|
||||
gpu.Submit(commands, {});
|
||||
|
||||
std::binary_semaphore ordered_started{0};
|
||||
std::atomic<bool> ordered_finished{false};
|
||||
@@ -2297,8 +2490,7 @@ public:
|
||||
label = 0;
|
||||
prefix = 0;
|
||||
suffix = 0;
|
||||
gpu.Submit(commands.data(), static_cast<uint32_t>(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<uint32_t>(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<uint32_t, 6> standard_payload{0x00400000u, 1u, 0u,
|
||||
0u, 0u, 10u};
|
||||
const std::array<uint32_t, 7> 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<std::array<uint64_t, 2>, 16> results;
|
||||
@@ -23156,7 +23347,7 @@ void CheckPm4SyntheticOcclusionCounterDump(RenderContext &renderer) {
|
||||
static_cast<uint32_t>(raw_address),
|
||||
static_cast<uint32_t>(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<uint32_t, 2> 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<uint32_t, 4> 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<uint32_t, 3> single{
|
||||
@@ -23226,8 +23416,7 @@ void CheckPm4GuardBandRegisterRanges(RenderContext &renderer) {
|
||||
std::bit_cast<uint32_t>(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<uint32_t>(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<std::pair<uint32_t, float>, 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<uint32_t>(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<uint32_t>(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<int>(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<Prospero::PrimitiveType>(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<uint32_t, 2> 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<uint64_t>(&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<uint64_t>(&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<uint32_t, 2> 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");
|
||||
|
||||
Reference in New Issue
Block a user