refactor renderer

This commit is contained in:
nmzik committed 2026-07-27 02:27:29 +02:00
1 parent a720b28b7f
commit a20cf5d298
112 files changed
+18269 -18368

No files matched your search

@@ -11,8 +11,6 @@
namespace Libs::Graphics {
inline constexpr uint32_t AcquireGcrGl2Writeback = 1u << 15u;
bool TestWaitRegMemValue(uint64_t value, uint64_t ref, uint64_t mask, uint32_t func);
enum class Pm4ProcessResult { Complete, Blocked };
@@ -45,7 +43,7 @@ public:
int64_t flip_arg = 0;
};
CommandProcessor() = default;
explicit CommandProcessor(RenderContext& renderer): m_renderer(renderer) {}
~CommandProcessor() = default;
KYTY_CLASS_NO_COPY(CommandProcessor);
@@ -60,16 +58,13 @@ public:
if (m_readback_active) {
EXIT("nested command-processor readback transaction\n");
}
m_readback_active = true;
m_readback_finished = false;
m_readback_active = true;
}
void FinishReadbackTransaction();
void EndReadbackTransaction() {
if (!m_readback_active) {
EXIT("command-processor readback transaction is not active\n");
}
m_readback_active = false;
m_readback_finished = false;
m_readback_active = false;
}
HW::Context& GetCtx() { return m_ctx; }
@@ -106,12 +101,10 @@ public:
void Flip(void* dst_gpu_addr, uint32_t value);
void FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache_action, void* dst_gpu_addr,
uint32_t value);
void PrepareCpuFlip();
void PrepareCpuFlip(uint64_t request_id);
void SynchronizeGpu();
void MemoryBarrier();
void EmitGlobalBarrier();
void TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id);
void RenderTextureBarrier(uint64_t vaddr, uint64_t size);
void DepthStencilBarrier(uint64_t vaddr, uint64_t size);
void DispatchDirect(uint32_t thread_group_x, uint32_t thread_group_y, uint32_t thread_group_z,
uint32_t mode);
void DispatchIndirect(uint32_t data_offset, uint32_t mode);
@@ -160,11 +153,12 @@ private:
void ProcessPm4(Pm4Execution& execution, size_t stop_depth);
void SuspendPm4();
CommandScheduler& GetScheduler() const { return GetRenderContext().GetCommandScheduler(); }
CommandScheduler& GetScheduler() const { return m_renderer.GetCommandScheduler(); }
RenderCommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
void CheckBuffer() const { GetScheduler().CheckActive(); }
GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); }
GpuResourceManager& GetGpuResources() const { return m_renderer.GetGpuResources(); }
RenderContext& m_renderer;
HW::Context m_ctx;
HW::UserConfig m_ucfg;
HW::Shader m_sh_ctx;
@@ -179,8 +173,7 @@ private:
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;
bool m_readback_active = false;
uint32_t m_const_ram[0x3000] = {0};
@@ -6,7 +6,6 @@
#include "graphics/guest_gpu/command_processor/pm4Dispatch.h"
#include "graphics/guest_gpu/graphicsRun.h"
#include "graphics/host_gpu/graphicContext.h"
#include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/presentation/videoOut.h"
@@ -1764,230 +1763,11 @@ static bool HwUcTrySetFakeRegisterRange(uint32_t cmd_offset, const uint32_t* buf
return true;
}
// NOLINTNEXTLINE(readability-function-cognitive-complexity)
KYTY_CP_OP_PARSER(CpOpAcquireMem) {
KYTY_PROFILER_FUNCTION();
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0055800 && cmd_id != 0xc0061050);
bool custom = (cmd_id == 0xc0061050);
uint32_t engine = buffer[0] >> 31u;
uint32_t stall_mode = (custom ? 1u : engine);
uint32_t cache_action = buffer[0] & 0x7fffffffu;
uint64_t size_lo = buffer[1];
uint32_t size_hi = buffer[2];
uint64_t base_lo = buffer[3];
uint32_t base_hi = buffer[4];
uint32_t poll = buffer[5];
[[maybe_unused]] uint32_t gcr_cntl = (custom ? buffer[6] : 0);
uint32_t target_mask = cache_action & 0x00007FC0u;
uint32_t extended_action = cache_action & 0x2E000000u;
uint32_t action =
((cache_action & 0x00C00000u) >> 0x12u) | ((cache_action & 0x00058000u) >> 0xfu);
if (custom && engine > 1) {
LOGF("\t warning: custom acquire_mem unsupported engine: %" PRIu32 "\n", engine);
}
// EXIT_NOT_IMPLEMENTED(stall_mode != 1);
EXIT_NOT_IMPLEMENTED(size_hi != 0);
EXIT_NOT_IMPLEMENTED(base_hi != 0);
if (poll != 10) {
LOGF("\t warning: acquire_mem unexpected poll interval: %" PRIu32 "\n", poll);
}
switch (cache_action) {
case 0x00000000: {
if (custom && gcr_cntl != 0) {
LOGF("\t custom acquire_mem GCR-only barrier, gcr_cntl = 0x%08" PRIx32
", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n",
gcr_cntl, base_lo << 8u, size_lo << 8u);
cp.MemoryBarrier();
if ((gcr_cntl & AcquireGcrGl2Writeback) != 0) {
cp.SynchronizeGpu();
}
}
} break;
case 0x00000040:
case 0x00003fc0:
case 0x00004000:
case 0x00007fc0: {
// target_mask set, no CB/DB action bits. Treat as an ordering barrier.
EXIT_IF(target_mask != cache_action);
EXIT_IF(extended_action != 0x00000000);
EXIT_IF(action != 0x00);
LOGF("\t temporary: acquire_mem target-mask-only barrier, target_mask = 0x%08" PRIx32
", gcr_cntl = 0x%08" PRIx32 ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n",
target_mask, gcr_cntl, base_lo << 8u, size_lo << 8u);
cp.MemoryBarrier();
} break;
case 0x02000000: {
// target_mask: 0x00000000 (none)
// extended_action: 0x02000000 (FlushAndInvalidateCbCache)
// action: 0x00 (none)
EXIT_IF(target_mask != 0x00000000);
EXIT_IF(extended_action != 0x02000000);
EXIT_IF(action != 0x00);
LOGF("\t temporary: acquire_mem CB-cache-only barrier, gcr_cntl = 0x%08" PRIx32
", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n",
gcr_cntl, base_lo << 8u, size_lo << 8u);
cp.MemoryBarrier();
} break;
case 0x04000000: {
// target_mask: 0x00000000 (none)
// extended_action: 0x04000000 (FlushAndInvalidateDbCache)
// action: 0x00 (none)
EXIT_IF(target_mask != 0x00000000);
EXIT_IF(extended_action != 0x04000000);
EXIT_IF(action != 0x00);
LOGF("\t temporary: acquire_mem DB-cache-only barrier, gcr_cntl = 0x%08" PRIx32
", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n",
gcr_cntl, base_lo << 8u, size_lo << 8u);
cp.MemoryBarrier();
} break;
case 0x04004000:
case 0x04007fc0: {
// target_mask: 0x00004000 (Depth Target), 0x00007fc0 (all rt and depth)
// extended_action: 0x04000000 (FlushAndInvalidateDbCache)
// action: 0x00 (none)
EXIT_IF(target_mask != 0x00004000 && target_mask != 0x00007FC0);
EXIT_IF(extended_action != 0x04000000);
EXIT_IF(action != 0x00);
LOGF("\t temporary: acquire_mem DB target barrier, target_mask = 0x%08" PRIx32
", gcr_cntl = 0x%08" PRIx32 ", base = 0x%016" PRIx64 ", size = 0x%016" PRIx64 "\n",
target_mask, gcr_cntl, base_lo << 8u, size_lo << 8u);
if (size_lo != 0) {
cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u);
} else {
cp.MemoryBarrier();
}
} break;
case 0x02c40040:
case 0x02c43fc0:
case 0x02c47fc0: {
// target_mask: 0x00000040 (rt0), 0x00003fc0 (all rt), 0x00007fc0 (all rt and depth)
// extended_action: 0x02000000 (FlushAndInvalidateCbCache)
// action: 0x38 (WriteBackAndInvalidateL1andL2)
EXIT_IF(target_mask != 0x00000040 && target_mask != 0x00003FC0 &&
target_mask != 0x00007FC0);
EXIT_IF(extended_action != 0x02000000);
EXIT_IF(action != 0x38);
EXIT_NOT_IMPLEMENTED(size_lo == 0);
EXIT_NOT_IMPLEMENTED(base_lo == 0);
cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u);
cp.SynchronizeGpu();
} break;
case 0x02003fc0:
case 0x02007fc0: {
// target_mask: 0x00003FC0 (all rt), 0x00007fc0 (all rt and depth)
// extended_action: 0x02000000 (FlushAndInvalidateCbCache)
// action: 0x00 (none)
EXIT_IF(target_mask != 0x00003FC0 && target_mask != 0x00007fc0);
EXIT_IF(extended_action != 0x02000000);
EXIT_IF(action != 0x00);
if (size_lo == 0) {
if (base_lo != 0) {
LOGF("\t warning: acquire_mem CB-cache barrier with non-zero base");
}
cp.MemoryBarrier();
} else {
EXIT_NOT_IMPLEMENTED(base_lo == 0);
cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u);
}
} break;
case 0x00C40000: {
// target_mask: 0x00000000 (none)
// extended_action: 0x00000000 (none)
// action: 0x38 (WriteBackAndInvalidateL1andL2)
EXIT_IF(target_mask != 0x00000000);
EXIT_IF(extended_action != 0x00000000);
EXIT_IF(action != 0x38);
EXIT_NOT_IMPLEMENTED(size_lo != 1);
EXIT_NOT_IMPLEMENTED(base_lo != 0);
cp.MemoryBarrier();
cp.SynchronizeGpu();
} break;
case 0x00400000: {
// target_mask: 0x00000000 (none)
// extended_action: 0x00000000 (none)
// action: 0x10 (InvalidateL1)
EXIT_IF(target_mask != 0x00000000);
EXIT_IF(extended_action != 0x00000000);
EXIT_IF(action != 0x10);
EXIT_NOT_IMPLEMENTED(size_lo != 1);
EXIT_NOT_IMPLEMENTED(base_lo != 0);
cp.MemoryBarrier();
} break;
case 0x04c44000: {
// target_mask: 0x00004000 (Depth Target)
// extended_action: 0x04000000 (FlushAndInvalidateDbCache)
// action: 0x38 (WriteBackAndInvalidateL1andL2)
EXIT_IF(target_mask != 0x00004000);
EXIT_IF(extended_action != 0x04000000);
EXIT_IF(action != 0x38);
cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u);
cp.SynchronizeGpu();
} break;
case 0x06000040:
case 0x06000080:
case 0x06003fc0:
case 0x06007fc0: {
// target_mask: 0x00000040 (rt0), 0x00000080 (rt1), 0x00003fc0 (all rt), 0x00007fc0
// (all rt and depth) extended_action: 0x06000000 (Flush Cb & Db) action: 0x00
// (none)
if (gcr_cntl != 0 && gcr_cntl != 0x280 && gcr_cntl != 0x300) {
LOGF("\t temporary: acquire_mem CB+DB barrier with unhandled GCR control "
"0x%08" PRIx32 "\n",
gcr_cntl);
}
EXIT_IF(target_mask != 0x00000040 && target_mask != 0x00000080 &&
target_mask != 0x00003fc0 && target_mask != 0x00007fc0);
EXIT_IF(extended_action != 0x06000000);
EXIT_IF(action != 0x00);
if (size_lo != 0) {
if ((target_mask & 0x00003fc0) != 0) {
cp.RenderTextureBarrier(base_lo << 8u, size_lo << 8u);
}
if ((target_mask & 0x00004000) != 0) {
cp.DepthStencilBarrier(base_lo << 8u, size_lo << 8u);
}
} else {
cp.MemoryBarrier();
}
} break;
default:
EXIT("unknown barrier: 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32 ", 0x%08" PRIx32
"\n",
cache_action, target_mask, extended_action, action);
}
if (stall_mode == 0) {
cp.BufferWait();
}
return (custom ? 7 : 6);
return (cmd_id == 0xc0061050 ? 7 : 6);
}
KYTY_CP_OP_PARSER(CpOpDispatchDirect) {
@@ -2930,7 +2710,7 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
if (data_sel == 0 || interrupt_selector == 4) {
if (eop_event_type != 0x28 || gcr_cntl != 0) {
cp.MemoryBarrier();
cp.EmitGlobalBarrier();
}
if (gl2_writeback) {
@@ -2944,7 +2724,7 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
if (release_dst == ReleaseMemDstMemory && dst_gpu_addr == nullptr) {
if (eop_event_type != 0x28 || gcr_cntl != 0) {
cp.MemoryBarrier();
cp.EmitGlobalBarrier();
}
if (gl2_writeback) {
@@ -2957,7 +2737,7 @@ KYTY_CP_OP_PARSER(CpOpReleaseMem) {
}
if (ReleaseMemGcrNeedsBarrier(eop_event_type, gcr_cntl)) {
cp.MemoryBarrier();
cp.EmitGlobalBarrier();
}
auto cache_action = ReleaseMemCacheActionFromGcr(gcr_cntl);
+314 -174
View File
@@ -10,11 +10,9 @@
#include "graphics/guest_gpu/command_processor/pm4Dispatch.h"
#include "graphics/guest_gpu/hardwareContext.h"
#include "graphics/guest_gpu/pm4.h"
#include "graphics/host_gpu/objects/label.h"
#include "graphics/host_gpu/renderer/render.h"
#include "graphics/host_gpu/renderer/renderContext.h"
#include "graphics/host_gpu/renderer/sync.h"
#include "graphics/presentation/displayBuffer.h"
#include "graphics/presentation/videoOut.h"
#include "graphics/presentation/window.h"
#include "graphics/shader/shader.h"
@@ -28,6 +26,8 @@
#include <cstdio>
#include <deque>
#include <memory>
#include <semaphore>
#include <thread>
#include <vector>
namespace Libs::Graphics {
@@ -36,6 +36,7 @@ static thread_local CommandProcessor* g_current_processor = nullptr;
static thread_local Pm4Execution* g_current_execution = nullptr;
static thread_local uint32_t g_submission_pause_depth = 0;
static thread_local bool g_gpu_mutex_owned = false;
static thread_local bool g_gpu_thread = false;
class GpuMutexLock final {
public:
@@ -75,32 +76,37 @@ private:
std::vector<uint32_t> m_words;
};
class Gpu {
class GpuState {
public:
static constexpr uint32_t ComputePipeCount = 7;
static constexpr uint32_t QueuesPerComputePipe = 8;
static constexpr uint32_t ComputeQueueCount = ComputePipeCount * QueuesPerComputePipe;
static constexpr uint32_t QueueCount = 1 + ComputeQueueCount;
Gpu() {
explicit GpuState(RenderContext& renderer): m_renderer(renderer) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
m_gfx_cp = std::make_unique<CommandProcessor>();
Common::Thread thread(ThreadRun, this);
thread.Detach();
m_gfx_cp = std::make_unique<CommandProcessor>(renderer);
m_thread = std::jthread(ThreadRun, this);
}
~Gpu() { KYTY_NOT_IMPLEMENTED; }
~GpuState();
KYTY_CLASS_NO_COPY(Gpu);
KYTY_CLASS_NO_COPY(GpuState);
void 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);
void SubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
bool trigger_agc_interrupt_on_done);
void SubmitFlipPreparation();
void SubmitFlipPreparation(uint64_t request_id);
void Done();
void PauseSubmissions();
void ResumeSubmissions();
void Shutdown();
[[nodiscard]] bool IsStopping();
void SendCommand(Common::UniqueFunction<void>&& command);
void SendCommandSync(Common::UniqueFunction<void>&& command);
void SendCommandSyncWithProcessor(Common::UniqueFunction<void, CommandProcessor&>&& command);
int GetFrameNum();
[[nodiscard]] static bool IsGpuThread() noexcept { return g_gpu_thread; }
private:
enum class SubmissionType { Graphics, Compute, FlipPreparation };
@@ -118,6 +124,7 @@ private:
bool command_complete = false;
bool constant_complete = false;
bool blocked = false;
uint64_t flip_request_id = 0;
};
void WaitLocked();
@@ -127,42 +134,100 @@ private:
static void ThreadRun(void* data);
CommandProcessor& GetProcessor(uint32_t queue_id);
RenderContext& m_renderer;
Common::Mutex m_submission_mutex;
Common::Mutex m_queue_mutex;
std::mutex m_shutdown_mutex;
Common::CondVar m_work_available;
Common::CondVar m_idle;
std::array<std::deque<Submission>, QueueCount> m_queues;
uint32_t m_next_queue = 0;
uint32_t m_submission_count = 0;
bool m_processing = false;
bool m_graphics_done = true;
std::deque<Common::UniqueFunction<void>> m_commands;
uint32_t m_next_queue = 0;
uint32_t m_submission_count = 0;
bool m_processing = false;
bool m_graphics_done = true;
bool m_accepting = true;
bool m_stopping = false;
bool m_shutdown_complete = false;
std::unique_ptr<CommandProcessor> m_gfx_cp;
std::array<std::unique_ptr<CommandProcessor>, ComputeQueueCount> m_compute_cp;
uint64_t m_submit_id = 0;
std::atomic_int m_done_num = 0;
std::jthread m_thread;
};
static Gpu* g_gpu = nullptr;
static bool GraphicsRunDebugDumpEnabled() {
return Config::GraphicsDebugDumpEnabled() &&
Config::GetPrintfDirection() != Config::OutputDirection::Silent;
}
void GraphicsRunInit() {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
EXIT_IF(g_gpu != nullptr);
GraphicsInitJmpTables();
g_gpu = new Gpu;
GpuState::~GpuState() {
Shutdown();
}
void Gpu::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) {
void GpuState::Shutdown() {
std::lock_guard shutdown_lock(m_shutdown_mutex);
if (m_shutdown_complete) {
return;
}
{
Common::LockGuard lock(m_queue_mutex);
m_accepting = false;
m_stopping = true;
m_work_available.SignalAll();
}
if (m_thread.joinable()) {
m_thread.join();
}
m_shutdown_complete = true;
}
bool GpuState::IsStopping() {
Common::LockGuard lock(m_queue_mutex);
return m_stopping;
}
void GpuState::SendCommand(Common::UniqueFunction<void>&& command) {
EXIT_IF(!command);
if (IsGpuThread()) {
command();
return;
}
Common::LockGuard lock(m_queue_mutex);
EXIT_IF(!m_accepting);
m_commands.push_back(std::move(command));
m_work_available.Signal();
}
void GpuState::SendCommandSync(Common::UniqueFunction<void>&& command) {
EXIT_IF(!command);
if (IsGpuThread()) {
command();
return;
}
std::binary_semaphore done {0};
SendCommand([operation = std::move(command), &done]() mutable {
operation();
done.release();
});
done.acquire();
}
void GpuState::SendCommandSyncWithProcessor(
Common::UniqueFunction<void, CommandProcessor&>&& command) {
EXIT_IF(!command);
SendCommandSync([this, operation = std::move(command)]() mutable {
EXIT_IF(g_current_processor != nullptr);
g_current_processor = m_gfx_cp.get();
operation(*m_gfx_cp);
g_current_processor = nullptr;
});
}
void GpuState::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) {
GpuMutexLock lock(m_submission_mutex);
Submission submission;
submission.type = SubmissionType::Graphics;
@@ -175,8 +240,8 @@ void Gpu::Submit(uint32_t* cmd_draw_buffer, uint32_t num_draw_dw, uint32_t* cmd_
Enqueue(std::move(submission));
}
void Gpu::SubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
bool trigger_agc_interrupt_on_done) {
void GpuState::SubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
bool trigger_agc_interrupt_on_done) {
GpuMutexLock lock(m_submission_mutex);
constexpr uint32_t compute_queue_base = 0x20u;
@@ -192,60 +257,52 @@ void Gpu::SubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
Enqueue(std::move(submission));
}
void Gpu::SubmitFlipPreparation() {
void GpuState::SubmitFlipPreparation(uint64_t request_id) {
GpuMutexLock lock(m_submission_mutex);
Submission submission;
submission.type = SubmissionType::FlipPreparation;
submission.queue_id = 0;
submission.reset_processor = m_graphics_done;
submission.flip_request_id = request_id;
m_graphics_done = false;
Enqueue(std::move(submission));
}
void Gpu::Done() {
void GpuState::Done() {
GpuMutexLock lock(m_submission_mutex);
WaitLocked();
if (IsGpuThread()) {
m_gfx_cp->BufferWait();
} else {
WaitLocked();
}
m_graphics_done = true;
m_done_num++;
}
int Gpu::GetFrameNum() {
int GpuState::GetFrameNum() {
return m_done_num;
}
void Gpu::WaitLocked() {
void GpuState::WaitLocked() {
WaitForIdle();
m_gfx_cp->BufferWait();
SendCommandSync([this] { m_gfx_cp->BufferWait(); });
}
CommandProcessor& Gpu::GetProcessor(uint32_t queue_id) {
CommandProcessor& GpuState::GetProcessor(uint32_t queue_id) {
EXIT_IF(queue_id >= QueueCount);
if (queue_id == 0) {
return *m_gfx_cp;
}
auto& processor = m_compute_cp[queue_id - 1];
if (processor == nullptr) {
processor = std::make_unique<CommandProcessor>();
processor = std::make_unique<CommandProcessor>(m_renderer);
}
return *processor;
}
void CommandProcessor::FinishReadbackTransaction() {
if (GraphicsRunCurrentCommandProcessor() != this || !m_readback_active) {
EXIT("GPU readback finish requires a command-processor thread\n");
}
if (m_readback_finished) {
return;
}
GetScheduler().FinishCurrent();
m_readback_finished = true;
}
void CommandProcessor::Reset() {
BufferWait();
Sync::DeleteBuffers();
m_sh_ctx.Reset();
m_ucfg.Reset();
m_ctx.Reset();
@@ -396,56 +453,83 @@ void CommandProcessor::DmaData(uint8_t engine, uint8_t dst_sel, uint8_t dst_cach
EXIT_NOT_IMPLEMENTED(wait_for_previous > 1);
EXIT_NOT_IMPLEMENTED(write_confirm > 1);
EXIT_NOT_IMPLEMENTED(block_engine > 1);
const bool dst_memory = dst_sel == 0 || dst_sel == 3;
const bool src_memory = src_sel == 0 || src_sel == 3;
if (!dst_memory) {
if (static_cast<uint32_t>(dst_address_or_offset) == 0x3022cu) {
return;
}
auto decode_gds = [](uint8_t selector, bool& is_gds) {
switch (selector) {
case 0:
case 3: is_gds = false; return true;
case 1: is_gds = true; return true;
default: return false;
}
};
bool dst_gds = false;
if (!decode_gds(dst_sel, dst_gds)) {
EXIT("unsupported dmaData destination selector 0x%02" PRIx8 "\n", dst_sel);
}
auto& buffer_cache = GetGpuResources().GetBufferCache();
if (src_sel == 2) {
GetGpuResources().FillBuffer(
CurrentBuffer(), dst_address_or_offset, num_bytes,
static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu));
buffer_cache.FillBuffer(
dst_address_or_offset, num_bytes,
static_cast<uint32_t>(src_address_or_offset_or_immediate & 0xffffffffu), dst_gds);
return;
}
if (src_memory) {
GetGpuResources().CopyBuffer(CurrentBuffer(), dst_address_or_offset,
src_address_or_offset_or_immediate, num_bytes);
return;
bool src_gds = false;
if (!decode_gds(src_sel, src_gds)) {
EXIT("unsupported dmaData source selector 0x%02" PRIx8 "\n", src_sel);
}
EXIT("unsupported dmaData source selector 0x%02" PRIx8 "\n", src_sel);
if (src_gds && dst_gds) {
EXIT("unsupported dmaData GDS-to-GDS copy\n");
}
buffer_cache.CopyBuffer(dst_address_or_offset, src_address_or_offset_or_immediate, num_bytes,
dst_gds, src_gds);
}
void Gpu::Enqueue(Submission submission) {
void GpuState::Enqueue(Submission submission) {
EXIT_IF(submission.queue_id >= QueueCount);
Common::LockGuard lock(m_queue_mutex);
EXIT_IF(!m_accepting);
m_queues[submission.queue_id].push_back(std::move(submission));
m_submission_count++;
m_work_available.Signal();
}
void Gpu::WaitForIdle() {
void GpuState::WaitForIdle() {
Common::LockGuard lock(m_queue_mutex);
while (m_processing || m_submission_count != 0) {
while (m_processing || !m_commands.empty() || m_submission_count != 0) {
m_idle.Wait(&m_queue_mutex);
}
}
void Gpu::ThreadRun(void* data) {
auto* gpu = static_cast<Gpu*>(data);
void GpuState::ThreadRun(void* data) {
auto* gpu = static_cast<GpuState*>(data);
EXIT_IF(gpu == nullptr);
KYTY_PROFILER_THREAD("Thread_Gpu");
g_gpu_thread = true;
for (;;) {
Submission submission;
Submission submission;
Common::UniqueFunction<void> command;
bool has_submission = false;
bool should_stop = false;
{
Common::LockGuard lock(gpu->m_queue_mutex);
int selected_queue = -1;
while (selected_queue < 0) {
while (gpu->m_submission_count == 0) {
gpu->m_processing = false;
gpu->m_idle.Signal();
gpu->m_work_available.Wait(&gpu->m_queue_mutex);
}
while (gpu->m_commands.empty() && gpu->m_submission_count == 0 && !gpu->m_stopping) {
gpu->m_processing = false;
gpu->m_idle.Signal();
gpu->m_work_available.Wait(&gpu->m_queue_mutex);
}
if (gpu->m_stopping && gpu->m_commands.empty() && gpu->m_submission_count == 0) {
gpu->m_processing = false;
gpu->m_idle.SignalAll();
should_stop = true;
} else if (!gpu->m_commands.empty()) {
command = std::move(gpu->m_commands.front());
gpu->m_commands.pop_front();
gpu->m_processing = true;
} else {
int selected_queue = -1;
for (uint32_t offset = 0; offset < QueueCount; offset++) {
const auto id = (gpu->m_next_queue + offset) % QueueCount;
if (!gpu->m_queues[id].empty() && !gpu->m_queues[id].front().blocked) {
@@ -461,16 +545,36 @@ void Gpu::ThreadRun(void* data) {
queue.front().blocked = false;
}
}
continue;
}
auto& queue = gpu->m_queues[static_cast<uint32_t>(selected_queue)];
submission = std::move(queue.front());
queue.pop_front();
gpu->m_submission_count--;
gpu->m_next_queue = (static_cast<uint32_t>(selected_queue) + 1) % QueueCount;
gpu->m_processing = true;
has_submission = true;
}
auto& queue = gpu->m_queues[static_cast<uint32_t>(selected_queue)];
submission = std::move(queue.front());
queue.pop_front();
gpu->m_submission_count--;
gpu->m_next_queue = (static_cast<uint32_t>(selected_queue) + 1) % QueueCount;
gpu->m_processing = true;
}
if (should_stop) {
gpu->m_gfx_cp->BufferWait();
g_gpu_thread = false;
return;
}
if (command) {
EXIT_IF(g_current_processor != nullptr);
command();
Common::LockGuard lock(gpu->m_queue_mutex);
gpu->m_processing = false;
if (gpu->m_commands.empty() && gpu->m_submission_count == 0) {
gpu->m_idle.SignalAll();
}
continue;
}
EXIT_IF(!has_submission);
const bool complete = gpu->Process(submission);
Common::LockGuard lock(gpu->m_queue_mutex);
@@ -486,13 +590,13 @@ void Gpu::ThreadRun(void* data) {
}
}
gpu->m_processing = false;
if (gpu->m_submission_count == 0) {
gpu->m_idle.Signal();
if (gpu->m_commands.empty() && gpu->m_submission_count == 0) {
gpu->m_idle.SignalAll();
}
}
}
bool Gpu::Process(Submission& submission) {
bool GpuState::Process(Submission& submission) {
auto& cp = GetProcessor(submission.queue_id);
const bool first_slice = !submission.started;
@@ -537,10 +641,15 @@ bool Gpu::Process(Submission& submission) {
}
}
if (progressed) {
if (complete) {
m_renderer.GetGpuResources().RunGarbageCollector();
}
cp.BufferFlush();
} else if (complete) {
m_renderer.GetGpuResources().RunGarbageCollector();
}
if (complete && submission.trigger_agc_interrupt_on_done) {
Sync::TriggerEopEvent(0);
m_renderer.TriggerEopEvent(0);
}
break;
}
@@ -561,30 +670,40 @@ bool Gpu::Process(Submission& submission) {
complete = cp.Process(submission.command_execution, buffer, num_dw) ==
Pm4ProcessResult::Complete;
if (submission.command_execution.MadeProgress()) {
if (complete) {
m_renderer.GetGpuResources().RunGarbageCollector();
}
cp.BufferFlush();
} else if (complete) {
m_renderer.GetGpuResources().RunGarbageCollector();
}
if (complete && submission.trigger_agc_interrupt_on_done) {
Sync::TriggerAgcUserInterrupt();
}
break;
}
case SubmissionType::FlipPreparation: cp.PrepareCpuFlip(); break;
case SubmissionType::FlipPreparation:
m_renderer.GetGpuResources().RunGarbageCollector();
cp.PrepareCpuFlip(submission.flip_request_id);
break;
}
return complete;
}
void Gpu::PauseSubmissions() {
void GpuState::PauseSubmissions() {
if (g_gpu_mutex_owned) {
EXIT("GPU submissions are already paused by this thread\n");
}
g_gpu_mutex_owned = true;
m_submission_mutex.Lock();
WaitLocked();
LabelDrain();
if (!IsGpuThread()) {
WaitLocked();
}
m_renderer.GetCommandScheduler().DrainPriorityOperations();
}
void Gpu::ResumeSubmissions() {
void GpuState::ResumeSubmissions() {
if (!g_gpu_mutex_owned) {
EXIT("GPU submissions resumed without an active pause\n");
}
@@ -823,9 +942,9 @@ void CommandProcessor::DrawIndex(uint32_t index_count, const void* index_addr, u
"\n",
vertex_offset_add, first_instance);
}
RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
flags, type, instance_count, render_target_slice_offset, vertex_offset_add,
first_instance);
m_renderer.GetRenderExecutor().DrawIndex(
m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr, flags, type,
instance_count, render_target_slice_offset, vertex_offset_add, first_instance);
}
void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_count,
@@ -843,8 +962,9 @@ void CommandProcessor::DrawIndexOffset(uint32_t index_offset, uint32_t index_cou
auto* index_addr = reinterpret_cast<const void*>(
m_index_base_addr + static_cast<uint64_t>(index_offset) * index_size);
RenderDrawIndex(m_submit_id, CurrentBuffer(), m_index_type_and_size, index_count, index_addr,
flags, 1, m_num_instances);
m_renderer.GetRenderExecutor().DrawIndex(m_submit_id, CurrentBuffer(),
m_index_type_and_size, index_count, index_addr,
flags, 1, m_num_instances);
}
void CommandProcessor::DrawIndirect(uint32_t data_offset, uint32_t draw_initiator, bool indexed) {
@@ -1036,7 +1156,7 @@ void CommandProcessor::DispatchDirect(uint32_t thread_group_x, uint32_t thread_g
{
CheckBuffer();
frame_num = GraphicsRunGetFrameNum();
frame_num = m_renderer.GetGpu().GetFrameNum();
if (GraphicsRunDebugDumpEnabled()) {
static std::atomic<uint32_t> log_count {0};
if (log_count.fetch_add(1, std::memory_order_relaxed) < 1024) {
@@ -1070,8 +1190,8 @@ void CommandProcessor::DispatchDirect(uint32_t thread_group_x, uint32_t thread_g
}
}
RenderDispatchDirect(m_submit_id, CurrentBuffer(), thread_group_x, thread_group_y,
thread_group_z, mode);
m_renderer.GetRenderExecutor().DispatchDirect(
m_submit_id, CurrentBuffer(), thread_group_x, thread_group_y, thread_group_z, mode);
}
constexpr uint32_t DispatchInitiatorUseThreadDimensions = 1u << 5u;
@@ -1117,15 +1237,16 @@ void CommandProcessor::DrawIndexAuto(uint32_t index_count, uint32_t flags,
uint32_t first_vertex, uint32_t first_instance) {
CheckBuffer();
RenderDrawIndexAuto(m_submit_id, CurrentBuffer(), index_count, flags,
render_target_slice_offset, instance_count, first_vertex, first_instance);
m_renderer.GetRenderExecutor().DrawAuto(
m_submit_id, CurrentBuffer(), index_count, flags, render_target_slice_offset,
instance_count, first_vertex, first_instance);
}
void CommandProcessor::WaitFlipDone(uint32_t video_out_handle, uint32_t display_buffer_index) {
BufferFlush();
VideoOut::VideoOutWaitFlipDone(static_cast<int>(video_out_handle),
static_cast<int>(display_buffer_index));
m_renderer.GetVideoOut().WaitFlipDone(static_cast<int>(video_out_handle),
static_cast<int>(display_buffer_index));
}
template <typename T>
@@ -1196,7 +1317,8 @@ void CommandProcessor::WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_wr
if (eop_event_type == 0x2f && cache_action == 0x00 && event_index == 0x06) {
auto* dst = static_cast<uint32_t*>(dst_gpu_addr);
SynchronizeGpu();
Sync::ReadGds(dst, value & 0xffffu, value >> 16u);
Sync::ReadGds(m_renderer.GetBufferCache().GetGdsBuffer(), dst,
value & 0xffffu, value >> 16u);
Sync::WriteAtEndOfPipeGds32(m_submit_id, CurrentBuffer(), dst, value & 0xffffu,
value >> 16u);
return;
@@ -1355,10 +1477,23 @@ void CommandProcessor::WriteAtEndOfPipe64(uint32_t cache_policy, uint32_t event_
interrupt_context_id);
}
void CommandProcessor::MemoryBarrier() {
void CommandProcessor::EmitGlobalBarrier() {
CheckBuffer();
GraphicsRenderMemoryBarrier(CurrentBuffer());
Common::LockGuard lock(m_renderer.GetMutex());
vk::MemoryBarrier2 barrier {};
barrier.srcStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.srcAccessMask = vk::AccessFlagBits2::eMemoryWrite;
barrier.dstStageMask = vk::PipelineStageFlagBits2::eAllCommands;
barrier.dstAccessMask =
vk::AccessFlagBits2::eMemoryRead | vk::AccessFlagBits2::eMemoryWrite;
vk::DependencyInfo dependency {};
dependency.memoryBarrierCount = 1;
dependency.pMemoryBarriers = &barrier;
GetScheduler().EndRendering();
CurrentBuffer().Handle().pipelineBarrier2(dependency);
}
void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id) {
@@ -1367,18 +1502,6 @@ void CommandProcessor::TriggerEopEventAtEndOfPipe(uint32_t interrupt_context_id)
Sync::TriggerEopEventAtEndOfPipe(CurrentBuffer(), interrupt_context_id);
}
void CommandProcessor::RenderTextureBarrier(uint64_t vaddr, uint64_t size) {
CheckBuffer();
GraphicsRenderTextureBarrier(CurrentBuffer(), vaddr, size);
}
void CommandProcessor::DepthStencilBarrier(uint64_t vaddr, uint64_t size) {
CheckBuffer();
GraphicsRenderDepthStencilBarrier(CurrentBuffer(), vaddr, size);
}
void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
if (GraphicsRunDebugDumpEnabled()) {
LOGF("CommandProcessor::TriggerEvent()\n"
@@ -1392,7 +1515,7 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
// CsPartialFlush, GsPartialFlush, PsPartialFlush.
case 0x00000007:
case 0x0000000f:
case 0x00000010: MemoryBarrier(); break;
case 0x00000010: EmitGlobalBarrier(); break;
// CbDbDataWritebackInvalidate, CbDataWritebackInvalidate.
case 0x00000016:
case 0x00000031:
@@ -1400,7 +1523,7 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type,
event_index);
}
MemoryBarrier();
EmitGlobalBarrier();
SynchronizeGpu();
break;
// DbDataWritebackInvalidate, DbMetadataWritebackInvalidate, CbMetadataWritebackInvalidate.
@@ -1411,7 +1534,7 @@ void CommandProcessor::TriggerEvent(uint32_t event_type, uint32_t event_index) {
EXIT("unknown event type: 0x%08" PRIx32 ", 0x%08" PRIx32 "\n", event_type,
event_index);
}
MemoryBarrier();
EmitGlobalBarrier();
break;
case 0x0000000d:
case 0x0000000e:
@@ -1441,8 +1564,8 @@ void CommandProcessor::Flip() {
}
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
auto request = Sync::PrepareVideoOutFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode,
m_flip.flip_arg);
Sync::WriteAtEndOfPipeOnlyFlip(m_submit_id, command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg, request);
GetScheduler().Flush();
@@ -1460,8 +1583,8 @@ void CommandProcessor::Flip(void* dst_gpu_addr, uint32_t value) {
std::memcpy(dst_gpu_addr, &value, sizeof(value));
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
auto request = Sync::PrepareVideoOutFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode,
m_flip.flip_arg);
Sync::WriteAtEndOfPipeWithFlip32(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);
@@ -1486,15 +1609,15 @@ void CommandProcessor::FlipWithInterrupt(uint32_t eop_event_type, uint32_t cache
}
std::memcpy(dst_gpu_addr, &value, sizeof(value));
auto& command = CurrentBuffer();
auto request = Sync::PrepareDisplayBufferFlip(command, m_flip.handle, m_flip.index,
m_flip.flip_mode, m_flip.flip_arg);
auto request = Sync::PrepareVideoOutFlip(command, m_flip.handle, m_flip.index, m_flip.flip_mode,
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);
GetScheduler().Flush();
}
void CommandProcessor::PrepareCpuFlip() {
void CommandProcessor::PrepareCpuFlip(uint64_t request_id) {
CheckBuffer();
if (g_current_processor != nullptr) {
EXIT("invalid graphics-thread CPU flip preparation\n");
@@ -1505,90 +1628,107 @@ void CommandProcessor::PrepareCpuFlip() {
};
ProcessorScope processor_scope(*this);
auto prepared_id = Presentation::DisplayBufferPrepareNextFlipOnGpu(CurrentBuffer());
m_renderer.GetVideoOut().PrepareFlip(request_id, CurrentBuffer());
GetScheduler().Flush();
Presentation::DisplayBufferCompleteFlipFromGpu(prepared_id);
m_renderer.GetVideoOut().CompleteFlip(request_id);
}
void CommandProcessor::SynchronizeGpu() {
GetScheduler().FinishCurrent();
}
void GraphicsRunSubmit(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) {
EXIT_IF(cmd_draw_buffer == nullptr);
EXIT_IF(num_draw_dw == 0);
EXIT_IF(g_gpu == nullptr);
g_gpu->Submit(cmd_draw_buffer, num_draw_dw, cmd_const_buffer, num_const_dw,
trigger_agc_interrupt_on_done);
Gpu::Gpu(RenderContext& renderer) {
EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread());
GraphicsInitJmpTables();
m_state = std::make_unique<GpuState>(renderer);
}
void GraphicsRunSubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
bool trigger_agc_interrupt_on_done) {
EXIT_IF(cmd_buffer == nullptr);
EXIT_IF(num_dw == 0);
EXIT_IF(g_gpu == nullptr);
Gpu::~Gpu() = default;
g_gpu->SubmitCompute(queue, cmd_buffer, num_dw, trigger_agc_interrupt_on_done);
void Gpu::Shutdown() {
m_state->Shutdown();
}
void GraphicsRunSubmitFlipPreparation() {
EXIT_IF(g_gpu == nullptr);
g_gpu->SubmitFlipPreparation();
bool Gpu::IsStopping() {
return m_state->IsStopping();
}
GraphicsRunSubmissionLock::GraphicsRunSubmissionLock() {
if (g_gpu == nullptr || g_current_processor != nullptr ||
g_submission_pause_depth == UINT32_MAX) {
void Gpu::SendCommand(Common::UniqueFunction<void>&& command) {
m_state->SendCommand(std::move(command));
}
void Gpu::SendCommandSync(Common::UniqueFunction<void>&& command) {
m_state->SendCommandSync(std::move(command));
}
void Gpu::SendCommandSyncWithProcessor(Common::UniqueFunction<void, CommandProcessor&>&& command) {
m_state->SendCommandSyncWithProcessor(std::move(command));
}
void Gpu::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) {
EXIT_IF(draw_commands == nullptr || draw_size_dw == 0);
m_state->Submit(draw_commands, draw_size_dw, constant_commands, constant_size_dw,
trigger_agc_interrupt_on_done);
}
void Gpu::SubmitCompute(uint32_t queue, uint32_t* commands, uint32_t size_dw,
bool trigger_agc_interrupt_on_done) {
EXIT_IF(commands == nullptr || size_dw == 0);
m_state->SubmitCompute(queue, commands, size_dw, trigger_agc_interrupt_on_done);
}
void Gpu::SubmitFlipPreparation(uint64_t request_id) {
m_state->SubmitFlipPreparation(request_id);
}
void Gpu::Done() {
m_state->Done();
}
int Gpu::GetFrameNum() const {
return m_state->GetFrameNum();
}
void Gpu::PauseSubmissions() {
m_state->PauseSubmissions();
}
void Gpu::ResumeSubmissions() {
m_state->ResumeSubmissions();
}
Gpu::SubmissionLock::SubmissionLock(Gpu& gpu): m_gpu(gpu) {
if (g_current_processor != nullptr || g_submission_pause_depth == UINT32_MAX) {
EXIT("cannot acquire GPU submission lock in the current state\n");
}
if (g_submission_pause_depth++ == 0) {
g_gpu->PauseSubmissions();
m_gpu.PauseSubmissions();
}
}
GraphicsRunSubmissionLock::~GraphicsRunSubmissionLock() {
if (g_gpu == nullptr || g_submission_pause_depth == 0) {
Gpu::SubmissionLock::~SubmissionLock() {
if (g_submission_pause_depth == 0) {
EXIT("GPU submission lock released without ownership\n");
}
if (--g_submission_pause_depth == 0) {
g_gpu->ResumeSubmissions();
m_gpu.ResumeSubmissions();
}
}
void GraphicsRunDone() {
EXIT_IF(g_gpu == nullptr);
g_gpu->Done();
}
int GraphicsRunGetFrameNum() {
EXIT_IF(g_gpu == nullptr);
return g_gpu->GetFrameNum();
}
bool GraphicsRunIsCommandProcessorThread() noexcept {
bool Gpu::IsCommandProcessorThread() noexcept {
return g_current_processor != nullptr;
}
CommandProcessor* GraphicsRunCurrentCommandProcessor() noexcept {
CommandProcessor* Gpu::CurrentCommandProcessor() noexcept {
return g_current_processor;
}
void GraphicsRunFinishScheduler() {
if (g_current_processor == nullptr) {
EXIT("GPU readback finish requires a command-processor thread\n");
}
g_current_processor->FinishReadbackTransaction();
}
bool GraphicsRunSubmissionLockHeld() noexcept {
bool Gpu::SubmissionLockHeld() noexcept {
return g_submission_pause_depth != 0;
}
bool GraphicsRunGpuLockHeld() noexcept {
bool Gpu::MutexHeld() noexcept {
return g_gpu_mutex_owned;
}
+46 -19
View File
@@ -3,32 +3,59 @@
#include "common/abi.h"
#include "common/common.h"
#include "common/uniqueFunction.h"
#include <memory>
namespace Libs::Graphics {
class CommandProcessor;
class GpuState;
class RenderContext;
class GraphicsRunSubmissionLock final {
class Gpu final {
public:
GraphicsRunSubmissionLock();
~GraphicsRunSubmissionLock();
KYTY_CLASS_NO_COPY(GraphicsRunSubmissionLock);
explicit Gpu(RenderContext& renderer);
~Gpu();
KYTY_CLASS_NO_COPY(Gpu);
void Shutdown();
[[nodiscard]] bool IsStopping();
void SendCommand(Common::UniqueFunction<void>&& command);
void SendCommandSync(Common::UniqueFunction<void>&& command);
void SendCommandSyncWithProcessor(Common::UniqueFunction<void, CommandProcessor&>&& 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();
[[nodiscard]] int GetFrameNum() const;
[[nodiscard]] static bool IsCommandProcessorThread() noexcept;
[[nodiscard]] static CommandProcessor* CurrentCommandProcessor() noexcept;
[[nodiscard]] static bool SubmissionLockHeld() noexcept;
[[nodiscard]] static bool MutexHeld() noexcept;
class SubmissionLock final {
public:
explicit SubmissionLock(Gpu& gpu);
~SubmissionLock();
KYTY_CLASS_NO_COPY(SubmissionLock);
private:
Gpu& m_gpu;
};
private:
friend class SubmissionLock;
void PauseSubmissions();
void ResumeSubmissions();
std::unique_ptr<GpuState> m_state;
};
void GraphicsRunInit();
void GraphicsRunSubmit(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 = false);
void GraphicsRunSubmitCompute(uint32_t queue, uint32_t* cmd_buffer, uint32_t num_dw,
bool trigger_agc_interrupt_on_done = false);
void GraphicsRunSubmitFlipPreparation();
void GraphicsRunDone();
int GraphicsRunGetFrameNum();
[[nodiscard]] bool GraphicsRunIsCommandProcessorThread() noexcept;
[[nodiscard]] CommandProcessor* GraphicsRunCurrentCommandProcessor() noexcept;
void GraphicsRunFinishScheduler();
[[nodiscard]] bool GraphicsRunSubmissionLockHeld() noexcept;
[[nodiscard]] bool GraphicsRunGpuLockHeld() noexcept;
} // namespace Libs::Graphics
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_GRAPHICSRUN_H_ */