mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
refactor renderer
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user