refactor renderer

This commit is contained in:
nmzik
2026-07-27 02:24:50 +02:00
parent a720b28b7f
commit a20cf5d298
112 changed files with 18269 additions and 18368 deletions
+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;
}