refactor(gpu): use a single ordered PM4 scheduler

This commit is contained in:
nmzik
2026-07-22 23:15:03 +02:00
parent dbcb444c05
commit f60007e923
12 changed files with 680 additions and 918 deletions
@@ -2,12 +2,10 @@
#define GRAPHICS_GUEST_GPU_COMMAND_PROCESSOR_COMMAND_PROCESSOR_H
#include "common/assert.h"
#include "common/threads.h"
#include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include <array>
#include <cstdint>
#include <vector>
@@ -17,94 +15,25 @@ inline constexpr uint32_t AcquireGcrGl2Writeback = 1u << 15u;
bool TestWaitRegMemValue(uint64_t value, uint64_t ref, uint64_t mask, uint32_t func);
class CommandScheduler {
enum class Pm4ProcessResult { Complete, Blocked };
class Pm4Execution {
public:
static constexpr int BuffersNum = 8;
CommandScheduler(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders)
: m_registers(registers), m_user_config(user_config), m_shaders(shaders) {}
bool Active() const { return m_current >= 0 && m_current < BuffersNum; }
void CheckActive() const { EXIT_IF(!Active()); }
RenderCommandBuffer& Current() const {
CheckActive();
EXIT_IF(m_buffers[m_current] == nullptr);
return *m_buffers[m_current];
}
void Init() {
if (m_current >= 0) {
return;
}
for (auto& buf: m_buffers) {
EXIT_IF(buf != nullptr);
buf = new RenderCommandBuffer(m_registers, m_user_config, m_shaders);
}
m_current = 0;
Current().Begin();
}
void Flush() {
SubmitCurrent();
BeginNext();
}
CommandBuffer& FlushAndGetSubmitted() {
auto& submitted = SubmitCurrent();
BeginNext();
return submitted;
}
void CopyBuffers(std::array<CommandBuffer*, BuffersNum>& out) const {
for (int i = 0; i < BuffersNum; i++) {
auto* buf = m_buffers[i];
EXIT_IF(buf == nullptr);
out[i] = buf;
}
}
void WaitAll() {
for (auto* buf: m_buffers) {
EXIT_IF(buf == nullptr);
buf->WaitForFenceAndReset();
}
}
void SubmitForReadback() {
if (!Active()) {
return;
}
SubmitCurrent();
}
void ResumeAfterReadback() {
if (!Active()) {
return;
}
Current().WaitForFenceAndReset();
Current().Begin();
}
[[nodiscard]] bool MadeProgress() const noexcept { return m_made_progress; }
private:
CommandBuffer& SubmitCurrent() {
auto& submitted = Current();
submitted.End();
submitted.Execute();
return submitted;
}
friend class CommandProcessor;
void BeginNext() {
m_current = (m_current + 1) % BuffersNum;
Current().WaitForFenceAndReset();
Current().Begin();
}
struct BufferCursor {
uint32_t* next_packet = nullptr;
uint32_t remaining_dw = 0;
uint32_t total_dw = 0;
uint32_t deferred_advance_dw = 0;
};
RenderCommandBuffer* m_buffers[BuffersNum] = {};
int m_current = -1;
HW::Context& m_registers;
HW::UserConfig& m_user_config;
HW::Shader& m_shaders;
std::vector<BufferCursor> m_buffer_stack;
bool m_suspended = false;
bool m_made_progress = false;
};
class CommandProcessor {
@@ -116,8 +45,8 @@ public:
int64_t flip_arg = 0;
};
CommandProcessor();
~CommandProcessor() { KYTY_NOT_IMPLEMENTED; }
CommandProcessor() = default;
~CommandProcessor() = default;
KYTY_CLASS_NO_COPY(CommandProcessor);
@@ -128,7 +57,6 @@ public:
void BufferFlushAndWait();
void BufferWait();
void BeginReadbackTransaction() {
m_mutex.Lock();
if (m_readback_active) {
EXIT("nested command-processor readback transaction\n");
}
@@ -142,12 +70,8 @@ public:
}
m_readback_active = false;
m_readback_finished = false;
m_mutex.Unlock();
}
void RunLock() { m_run_mutex.Lock(); }
void RunUnlock() { m_run_mutex.Unlock(); }
HW::Context& GetCtx() { return m_ctx; }
HW::UserConfig& GetUcfg() { return m_ucfg; }
HW::Shader& GetShCtx() { return m_sh_ctx; }
@@ -202,10 +126,11 @@ public:
void PrefetchL2(void* addr, uint32_t size) {}
void ResetDeCe();
void SetCeComplete(bool complete) { m_ce_complete = complete; }
void WaitCe();
void WaitDeDiff(uint32_t diff);
void IncremenetDe();
void IncremenetCe();
void IncrementDe();
void IncrementCe();
void WriteConstRam(uint32_t offset, const uint32_t* src, uint32_t dw_num);
void DumpConstRam(uint32_t* dst, uint32_t offset, uint32_t dw_num);
@@ -222,30 +147,26 @@ public:
const volatile void* address, uint32_t count_in_dwords);
[[nodiscard]] bool ShouldSkipPredicatedPackets() const { return m_predicate_skip; }
void Run(uint32_t* data, uint32_t num_dw);
Pm4ProcessResult Process(Pm4Execution& execution, uint32_t* buffer, uint32_t size_dw);
void ProcessIndirectBuffer(uint32_t* buffer, uint32_t size_dw);
[[nodiscard]] const FlipInfo& GetFlip() const { return m_flip; }
void SetFlip(const FlipInfo& flip) { m_flip = flip; }
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; }
private:
struct Counter {
Common::Mutex mutex;
Common::CondVar cond_var;
uint32_t value = 0;
};
template <typename T>
void WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_write_dest, uint32_t eop_event_type,
uint32_t cache_action, uint32_t event_index, uint32_t event_write_source,
void* dst_gpu_addr, T value, uint32_t interrupt_selector,
uint32_t interrupt_context_id);
void FinishCommandProcessors();
void ProcessPm4(Pm4Execution& execution, size_t stop_depth);
void SuspendPm4();
RenderCommandBuffer& CurrentBuffer() { return m_scheduler.Current(); }
void CheckBuffer() const { m_scheduler.CheckActive(); }
CommandScheduler& GetScheduler() const { return GetRenderContext().GetCommandScheduler(); }
RenderCommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
void CheckBuffer() const { GetScheduler().CheckActive(); }
GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); }
HW::Context m_ctx;
@@ -259,16 +180,11 @@ private:
uint64_t m_dispatch_indirect_args_base_addr = 0;
uint32_t m_num_instances = 1;
inline static Common::Mutex m_mutex;
inline static std::vector<CommandProcessor*> m_processors;
inline static bool m_readback_active = false;
inline static bool m_readback_finished = false;
Common::Mutex m_run_mutex;
CommandScheduler m_scheduler;
Counter m_de_counter;
Counter m_ce_counter;
uint32_t m_de_count = 0;
uint32_t m_ce_count = 0;
bool m_ce_complete = false;
bool m_readback_active = false;
bool m_readback_finished = false;
uint32_t m_const_ram[0x3000] = {0};
@@ -1984,7 +1984,6 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) {
}
if (stall_mode == 0) {
cp.BufferFlush();
cp.BufferWait();
}
@@ -2166,10 +2165,10 @@ KYTY_CP_OP_PARSER(CpOpBranch) {
reinterpret_cast<uint64_t>(else_buffer), else_num_dw);
if (take_then) {
cp.Run(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.Run(else_buffer, else_num_dw);
cp.ProcessIndirectBuffer(else_buffer, else_num_dw);
}
return payload_dw;
@@ -2496,7 +2495,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementCeCounter) {
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008400);
EXIT_NOT_IMPLEMENTED(buffer[0] != 1);
cp.IncremenetCe();
cp.IncrementCe();
return 1;
}
@@ -2507,7 +2506,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementDeCounter) {
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008500);
EXIT_NOT_IMPLEMENTED(buffer[0] != 0);
cp.IncremenetDe();
cp.IncrementDe();
return 1;
}
@@ -2607,7 +2606,7 @@ KYTY_CP_OP_PARSER(CpOpIndirectBuffer) {
GraphicsDbgDumpDcb("ci", indirect_num_dw, indirect_buffer);
cp.Run(indirect_buffer, indirect_num_dw);
cp.ProcessIndirectBuffer(indirect_buffer, indirect_num_dw);
return 3;
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -27,7 +27,7 @@ void GraphicsRunDone();
int GraphicsRunGetFrameNum();
[[nodiscard]] bool GraphicsRunIsCommandProcessorThread() noexcept;
[[nodiscard]] CommandProcessor* GraphicsRunCurrentCommandProcessor() noexcept;
void GraphicsRunFinishCommandProcessors();
void GraphicsRunFinishScheduler();
[[nodiscard]] bool GraphicsRunSubmissionLockHeld() noexcept;
[[nodiscard]] bool GraphicsRunGpuLockHeld() noexcept;
} // namespace Libs::Graphics