mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
refactor(gpu): use a single ordered PM4 scheduler
This commit is contained in:
@@ -1,96 +0,0 @@
|
||||
#ifndef EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_
|
||||
#define EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/profiler.h"
|
||||
#include "common/threads.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
class AsyncJob final {
|
||||
public:
|
||||
using Task = std::function<void()>;
|
||||
|
||||
explicit AsyncJob(std::string thread_name = {})
|
||||
: m_thread_name(std::move(thread_name)), m_worker_thread(WorkerEntry, this) {}
|
||||
|
||||
~AsyncJob() {
|
||||
{
|
||||
Common::LockGuard lock(m_mutex);
|
||||
m_stop_requested = true;
|
||||
m_task_available_condition.Signal();
|
||||
}
|
||||
|
||||
m_worker_thread.Join();
|
||||
}
|
||||
|
||||
KYTY_CLASS_NO_COPY(AsyncJob);
|
||||
|
||||
void Execute(Task task) {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
while (m_is_busy) {
|
||||
m_idle_condition.Wait(&m_mutex);
|
||||
}
|
||||
|
||||
m_task = std::move(task);
|
||||
m_is_busy = true;
|
||||
m_task_available_condition.Signal();
|
||||
}
|
||||
|
||||
void Wait() {
|
||||
Common::LockGuard lock(m_mutex);
|
||||
while (m_is_busy) {
|
||||
m_idle_condition.Wait(&m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void WorkerEntry(void* data) { static_cast<AsyncJob*>(data)->WorkerLoop(); }
|
||||
|
||||
void WorkerLoop() {
|
||||
if (!m_thread_name.empty()) {
|
||||
KYTY_PROFILER_THREAD(m_thread_name.c_str());
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
Task task;
|
||||
{
|
||||
Common::LockGuard lock(m_mutex);
|
||||
while (!m_is_busy && !m_stop_requested) {
|
||||
m_task_available_condition.Wait(&m_mutex);
|
||||
}
|
||||
|
||||
if (!m_is_busy) {
|
||||
return;
|
||||
}
|
||||
|
||||
task = std::move(m_task);
|
||||
}
|
||||
|
||||
task();
|
||||
|
||||
{
|
||||
Common::LockGuard lock(m_mutex);
|
||||
m_is_busy = false;
|
||||
m_idle_condition.SignalAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string m_thread_name;
|
||||
Common::Mutex m_mutex;
|
||||
Common::CondVar m_task_available_condition;
|
||||
Common::CondVar m_idle_condition;
|
||||
Task m_task;
|
||||
bool m_is_busy = false;
|
||||
bool m_stop_requested = false;
|
||||
Common::Thread m_worker_thread;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif /* EMULATOR_INCLUDE_EMULATOR_GRAPHICS_ASYNCJOB_H_ */
|
||||
@@ -2,12 +2,10 @@
|
||||
#define GRAPHICS_GUEST_GPU_COMMAND_PROCESSOR_COMMAND_PROCESSOR_H
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/threads.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
#include "graphics/host_gpu/renderer/renderContext.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
@@ -17,94 +15,25 @@ inline constexpr uint32_t AcquireGcrGl2Writeback = 1u << 15u;
|
||||
|
||||
bool TestWaitRegMemValue(uint64_t value, uint64_t ref, uint64_t mask, uint32_t func);
|
||||
|
||||
class CommandScheduler {
|
||||
enum class Pm4ProcessResult { Complete, Blocked };
|
||||
|
||||
class Pm4Execution {
|
||||
public:
|
||||
static constexpr int BuffersNum = 8;
|
||||
|
||||
CommandScheduler(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders)
|
||||
: m_registers(registers), m_user_config(user_config), m_shaders(shaders) {}
|
||||
|
||||
bool Active() const { return m_current >= 0 && m_current < BuffersNum; }
|
||||
void CheckActive() const { EXIT_IF(!Active()); }
|
||||
|
||||
RenderCommandBuffer& Current() const {
|
||||
CheckActive();
|
||||
EXIT_IF(m_buffers[m_current] == nullptr);
|
||||
return *m_buffers[m_current];
|
||||
}
|
||||
|
||||
void Init() {
|
||||
if (m_current >= 0) {
|
||||
return;
|
||||
}
|
||||
for (auto& buf: m_buffers) {
|
||||
EXIT_IF(buf != nullptr);
|
||||
buf = new RenderCommandBuffer(m_registers, m_user_config, m_shaders);
|
||||
}
|
||||
m_current = 0;
|
||||
Current().Begin();
|
||||
}
|
||||
|
||||
void Flush() {
|
||||
SubmitCurrent();
|
||||
BeginNext();
|
||||
}
|
||||
|
||||
CommandBuffer& FlushAndGetSubmitted() {
|
||||
auto& submitted = SubmitCurrent();
|
||||
BeginNext();
|
||||
return submitted;
|
||||
}
|
||||
|
||||
void CopyBuffers(std::array<CommandBuffer*, BuffersNum>& out) const {
|
||||
for (int i = 0; i < BuffersNum; i++) {
|
||||
auto* buf = m_buffers[i];
|
||||
EXIT_IF(buf == nullptr);
|
||||
out[i] = buf;
|
||||
}
|
||||
}
|
||||
|
||||
void WaitAll() {
|
||||
for (auto* buf: m_buffers) {
|
||||
EXIT_IF(buf == nullptr);
|
||||
buf->WaitForFenceAndReset();
|
||||
}
|
||||
}
|
||||
|
||||
void SubmitForReadback() {
|
||||
if (!Active()) {
|
||||
return;
|
||||
}
|
||||
SubmitCurrent();
|
||||
}
|
||||
|
||||
void ResumeAfterReadback() {
|
||||
if (!Active()) {
|
||||
return;
|
||||
}
|
||||
Current().WaitForFenceAndReset();
|
||||
Current().Begin();
|
||||
}
|
||||
[[nodiscard]] bool MadeProgress() const noexcept { return m_made_progress; }
|
||||
|
||||
private:
|
||||
CommandBuffer& SubmitCurrent() {
|
||||
auto& submitted = Current();
|
||||
submitted.End();
|
||||
submitted.Execute();
|
||||
return submitted;
|
||||
}
|
||||
friend class CommandProcessor;
|
||||
|
||||
void BeginNext() {
|
||||
m_current = (m_current + 1) % BuffersNum;
|
||||
Current().WaitForFenceAndReset();
|
||||
Current().Begin();
|
||||
}
|
||||
struct BufferCursor {
|
||||
uint32_t* next_packet = nullptr;
|
||||
uint32_t remaining_dw = 0;
|
||||
uint32_t total_dw = 0;
|
||||
uint32_t deferred_advance_dw = 0;
|
||||
};
|
||||
|
||||
RenderCommandBuffer* m_buffers[BuffersNum] = {};
|
||||
int m_current = -1;
|
||||
HW::Context& m_registers;
|
||||
HW::UserConfig& m_user_config;
|
||||
HW::Shader& m_shaders;
|
||||
std::vector<BufferCursor> m_buffer_stack;
|
||||
bool m_suspended = false;
|
||||
bool m_made_progress = false;
|
||||
};
|
||||
|
||||
class CommandProcessor {
|
||||
@@ -116,8 +45,8 @@ public:
|
||||
int64_t flip_arg = 0;
|
||||
};
|
||||
|
||||
CommandProcessor();
|
||||
~CommandProcessor() { KYTY_NOT_IMPLEMENTED; }
|
||||
CommandProcessor() = default;
|
||||
~CommandProcessor() = default;
|
||||
|
||||
KYTY_CLASS_NO_COPY(CommandProcessor);
|
||||
|
||||
@@ -128,7 +57,6 @@ public:
|
||||
void BufferFlushAndWait();
|
||||
void BufferWait();
|
||||
void BeginReadbackTransaction() {
|
||||
m_mutex.Lock();
|
||||
if (m_readback_active) {
|
||||
EXIT("nested command-processor readback transaction\n");
|
||||
}
|
||||
@@ -142,12 +70,8 @@ public:
|
||||
}
|
||||
m_readback_active = false;
|
||||
m_readback_finished = false;
|
||||
m_mutex.Unlock();
|
||||
}
|
||||
|
||||
void RunLock() { m_run_mutex.Lock(); }
|
||||
void RunUnlock() { m_run_mutex.Unlock(); }
|
||||
|
||||
HW::Context& GetCtx() { return m_ctx; }
|
||||
HW::UserConfig& GetUcfg() { return m_ucfg; }
|
||||
HW::Shader& GetShCtx() { return m_sh_ctx; }
|
||||
@@ -202,10 +126,11 @@ public:
|
||||
|
||||
void PrefetchL2(void* addr, uint32_t size) {}
|
||||
void ResetDeCe();
|
||||
void SetCeComplete(bool complete) { m_ce_complete = complete; }
|
||||
void WaitCe();
|
||||
void WaitDeDiff(uint32_t diff);
|
||||
void IncremenetDe();
|
||||
void IncremenetCe();
|
||||
void IncrementDe();
|
||||
void IncrementCe();
|
||||
|
||||
void WriteConstRam(uint32_t offset, const uint32_t* src, uint32_t dw_num);
|
||||
void DumpConstRam(uint32_t* dst, uint32_t offset, uint32_t dw_num);
|
||||
@@ -222,30 +147,26 @@ public:
|
||||
const volatile void* address, uint32_t count_in_dwords);
|
||||
[[nodiscard]] bool ShouldSkipPredicatedPackets() const { return m_predicate_skip; }
|
||||
|
||||
void Run(uint32_t* data, uint32_t num_dw);
|
||||
Pm4ProcessResult Process(Pm4Execution& execution, uint32_t* buffer, uint32_t size_dw);
|
||||
void ProcessIndirectBuffer(uint32_t* buffer, uint32_t size_dw);
|
||||
|
||||
[[nodiscard]] const FlipInfo& GetFlip() const { return m_flip; }
|
||||
void SetFlip(const FlipInfo& flip) { m_flip = flip; }
|
||||
void SetFlip(const FlipInfo& flip) { m_flip = flip; }
|
||||
|
||||
[[nodiscard]] uint64_t GetSubmitId() const { return m_submit_id; }
|
||||
void SetSubmitId(uint64_t submit_id) { m_submit_id = submit_id; }
|
||||
|
||||
private:
|
||||
struct Counter {
|
||||
Common::Mutex mutex;
|
||||
Common::CondVar cond_var;
|
||||
uint32_t value = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void WriteAtEndOfPipe(uint32_t cache_policy, uint32_t event_write_dest, uint32_t eop_event_type,
|
||||
uint32_t cache_action, uint32_t event_index, uint32_t event_write_source,
|
||||
void* dst_gpu_addr, T value, uint32_t interrupt_selector,
|
||||
uint32_t interrupt_context_id);
|
||||
void FinishCommandProcessors();
|
||||
void ProcessPm4(Pm4Execution& execution, size_t stop_depth);
|
||||
void SuspendPm4();
|
||||
|
||||
RenderCommandBuffer& CurrentBuffer() { return m_scheduler.Current(); }
|
||||
void CheckBuffer() const { m_scheduler.CheckActive(); }
|
||||
CommandScheduler& GetScheduler() const { return GetRenderContext().GetCommandScheduler(); }
|
||||
RenderCommandBuffer& CurrentBuffer() { return GetScheduler().Current(); }
|
||||
void CheckBuffer() const { GetScheduler().CheckActive(); }
|
||||
GpuResourceManager& GetGpuResources() const { return GetRenderContext().GetGpuResources(); }
|
||||
|
||||
HW::Context m_ctx;
|
||||
@@ -259,16 +180,11 @@ private:
|
||||
uint64_t m_dispatch_indirect_args_base_addr = 0;
|
||||
uint32_t m_num_instances = 1;
|
||||
|
||||
inline static Common::Mutex m_mutex;
|
||||
inline static std::vector<CommandProcessor*> m_processors;
|
||||
inline static bool m_readback_active = false;
|
||||
inline static bool m_readback_finished = false;
|
||||
Common::Mutex m_run_mutex;
|
||||
|
||||
CommandScheduler m_scheduler;
|
||||
|
||||
Counter m_de_counter;
|
||||
Counter m_ce_counter;
|
||||
uint32_t m_de_count = 0;
|
||||
uint32_t m_ce_count = 0;
|
||||
bool m_ce_complete = false;
|
||||
bool m_readback_active = false;
|
||||
bool m_readback_finished = false;
|
||||
|
||||
uint32_t m_const_ram[0x3000] = {0};
|
||||
|
||||
|
||||
@@ -1984,7 +1984,6 @@ KYTY_CP_OP_PARSER(CpOpAcquireMem) {
|
||||
}
|
||||
|
||||
if (stall_mode == 0) {
|
||||
cp.BufferFlush();
|
||||
cp.BufferWait();
|
||||
}
|
||||
|
||||
@@ -2166,10 +2165,10 @@ KYTY_CP_OP_PARSER(CpOpBranch) {
|
||||
reinterpret_cast<uint64_t>(else_buffer), else_num_dw);
|
||||
|
||||
if (take_then) {
|
||||
cp.Run(then_buffer, then_num_dw);
|
||||
cp.ProcessIndirectBuffer(then_buffer, then_num_dw);
|
||||
} else if (mode == 2 && else_num_dw != 0) {
|
||||
EXIT_NOT_IMPLEMENTED(else_buffer == nullptr);
|
||||
cp.Run(else_buffer, else_num_dw);
|
||||
cp.ProcessIndirectBuffer(else_buffer, else_num_dw);
|
||||
}
|
||||
|
||||
return payload_dw;
|
||||
@@ -2496,7 +2495,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementCeCounter) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008400);
|
||||
EXIT_NOT_IMPLEMENTED(buffer[0] != 1);
|
||||
|
||||
cp.IncremenetCe();
|
||||
cp.IncrementCe();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2507,7 +2506,7 @@ KYTY_CP_OP_PARSER(CpOpIncrementDeCounter) {
|
||||
EXIT_NOT_IMPLEMENTED(cmd_id != 0xC0008500);
|
||||
EXIT_NOT_IMPLEMENTED(buffer[0] != 0);
|
||||
|
||||
cp.IncremenetDe();
|
||||
cp.IncrementDe();
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -2607,7 +2606,7 @@ KYTY_CP_OP_PARSER(CpOpIndirectBuffer) {
|
||||
|
||||
GraphicsDbgDumpDcb("ci", indirect_num_dw, indirect_buffer);
|
||||
|
||||
cp.Run(indirect_buffer, indirect_num_dw);
|
||||
cp.ProcessIndirectBuffer(indirect_buffer, indirect_num_dw);
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,7 @@ void GraphicsRunDone();
|
||||
int GraphicsRunGetFrameNum();
|
||||
[[nodiscard]] bool GraphicsRunIsCommandProcessorThread() noexcept;
|
||||
[[nodiscard]] CommandProcessor* GraphicsRunCurrentCommandProcessor() noexcept;
|
||||
void GraphicsRunFinishCommandProcessors();
|
||||
void GraphicsRunFinishScheduler();
|
||||
[[nodiscard]] bool GraphicsRunSubmissionLockHeld() noexcept;
|
||||
[[nodiscard]] bool GraphicsRunGpuLockHeld() noexcept;
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -554,7 +554,7 @@ bool BufferCache::InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint6
|
||||
return action == CpuFaultAction::Continue;
|
||||
}
|
||||
if (GraphicsRunIsCommandProcessorThread()) {
|
||||
GraphicsRunFinishCommandProcessors();
|
||||
GraphicsRunFinishScheduler();
|
||||
}
|
||||
m_readback->Request(access, vaddr, size);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "graphics/host_gpu/renderer/commandScheduler.h"
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
void CommandScheduler::Begin(HW::Context& registers, HW::UserConfig& user_config,
|
||||
HW::Shader& shaders) {
|
||||
m_registers = ®isters;
|
||||
m_user_config = &user_config;
|
||||
m_shaders = &shaders;
|
||||
|
||||
if (!Active()) {
|
||||
for (auto& buffer: m_buffers) {
|
||||
buffer = std::make_unique<RenderCommandBuffer>();
|
||||
}
|
||||
m_current = 0;
|
||||
}
|
||||
|
||||
BindCurrent();
|
||||
if (!m_recording) {
|
||||
Current().Begin();
|
||||
m_recording = true;
|
||||
}
|
||||
}
|
||||
|
||||
void CommandScheduler::Flush() {
|
||||
SubmitCurrent();
|
||||
BeginNext();
|
||||
}
|
||||
|
||||
CommandBuffer& CommandScheduler::FlushAndGetSubmitted() {
|
||||
auto& submitted = SubmitCurrent();
|
||||
BeginNext();
|
||||
return submitted;
|
||||
}
|
||||
|
||||
void CommandScheduler::Finish() {
|
||||
CheckActive();
|
||||
if (m_recording) {
|
||||
SubmitCurrent();
|
||||
}
|
||||
for (auto& buffer: m_buffers) {
|
||||
buffer->WaitForFenceAndReset();
|
||||
}
|
||||
BindCurrent();
|
||||
Current().Begin();
|
||||
m_recording = true;
|
||||
}
|
||||
|
||||
void CommandScheduler::FinishCurrent() {
|
||||
auto& submitted = SubmitCurrent();
|
||||
submitted.WaitForFenceAndReset();
|
||||
submitted.Begin();
|
||||
m_recording = true;
|
||||
}
|
||||
|
||||
void CommandScheduler::CheckActive() const {
|
||||
EXIT_IF(!Active() || m_current >= BufferCount);
|
||||
}
|
||||
|
||||
RenderCommandBuffer& CommandScheduler::Current() const {
|
||||
CheckActive();
|
||||
EXIT_IF(m_buffers[m_current] == nullptr);
|
||||
return *m_buffers[m_current];
|
||||
}
|
||||
|
||||
void CommandScheduler::BindCurrent() const {
|
||||
EXIT_IF(m_registers == nullptr || m_user_config == nullptr || m_shaders == nullptr);
|
||||
Current().Bind(*m_registers, *m_user_config, *m_shaders);
|
||||
}
|
||||
|
||||
CommandBuffer& CommandScheduler::SubmitCurrent() {
|
||||
CheckActive();
|
||||
EXIT_IF(!m_recording);
|
||||
auto& submitted = Current();
|
||||
submitted.End();
|
||||
submitted.Execute();
|
||||
m_recording = false;
|
||||
return submitted;
|
||||
}
|
||||
|
||||
void CommandScheduler::BeginNext() {
|
||||
EXIT_IF(m_recording);
|
||||
m_current = (m_current + 1) % BufferCount;
|
||||
Current().WaitForFenceAndReset();
|
||||
BindCurrent();
|
||||
Current().Begin();
|
||||
m_recording = true;
|
||||
}
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
@@ -0,0 +1,45 @@
|
||||
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_
|
||||
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "graphics/host_gpu/renderer/render.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
namespace Libs::Graphics {
|
||||
|
||||
class CommandScheduler {
|
||||
public:
|
||||
static constexpr int BufferCount = 8;
|
||||
|
||||
CommandScheduler() = default;
|
||||
~CommandScheduler() = default;
|
||||
KYTY_CLASS_NO_COPY(CommandScheduler);
|
||||
|
||||
void Begin(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders);
|
||||
void Flush();
|
||||
CommandBuffer& FlushAndGetSubmitted();
|
||||
void Finish();
|
||||
void FinishCurrent();
|
||||
|
||||
[[nodiscard]] bool Active() const noexcept { return m_current >= 0; }
|
||||
void CheckActive() const;
|
||||
RenderCommandBuffer& Current() const;
|
||||
|
||||
private:
|
||||
void BindCurrent() const;
|
||||
CommandBuffer& SubmitCurrent();
|
||||
void BeginNext();
|
||||
|
||||
std::array<std::unique_ptr<RenderCommandBuffer>, BufferCount> m_buffers;
|
||||
int m_current = -1;
|
||||
bool m_recording = false;
|
||||
HW::Context* m_registers = nullptr;
|
||||
HW::UserConfig* m_user_config = nullptr;
|
||||
HW::Shader* m_shaders = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_COMMANDSCHEDULER_H_
|
||||
@@ -129,17 +129,22 @@ private:
|
||||
|
||||
class RenderCommandBuffer final: public CommandBuffer {
|
||||
public:
|
||||
RenderCommandBuffer(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders)
|
||||
: m_registers(registers), m_user_config(user_config), m_shaders(shaders) {}
|
||||
RenderCommandBuffer() = default;
|
||||
|
||||
[[nodiscard]] HW::Context& GetRegisters() const noexcept { return m_registers; }
|
||||
[[nodiscard]] HW::UserConfig& GetUserConfig() const noexcept { return m_user_config; }
|
||||
[[nodiscard]] HW::Shader& GetShaders() const noexcept { return m_shaders; }
|
||||
void Bind(HW::Context& registers, HW::UserConfig& user_config, HW::Shader& shaders) noexcept {
|
||||
m_registers = ®isters;
|
||||
m_user_config = &user_config;
|
||||
m_shaders = &shaders;
|
||||
}
|
||||
|
||||
[[nodiscard]] HW::Context& GetRegisters() const noexcept { return *m_registers; }
|
||||
[[nodiscard]] HW::UserConfig& GetUserConfig() const noexcept { return *m_user_config; }
|
||||
[[nodiscard]] HW::Shader& GetShaders() const noexcept { return *m_shaders; }
|
||||
|
||||
private:
|
||||
HW::Context& m_registers;
|
||||
HW::UserConfig& m_user_config;
|
||||
HW::Shader& m_shaders;
|
||||
HW::Context* m_registers = nullptr;
|
||||
HW::UserConfig* m_user_config = nullptr;
|
||||
HW::Shader* m_shaders = nullptr;
|
||||
};
|
||||
|
||||
void RenderDrawIndex(uint64_t submit_id, RenderCommandBuffer& buffer, uint32_t index_type_and_size,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/common.h"
|
||||
#include "common/threads.h"
|
||||
#include "graphics/host_gpu/renderer/bufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/commandScheduler.h"
|
||||
#include "graphics/host_gpu/renderer/descriptorCache.h"
|
||||
#include "graphics/host_gpu/renderer/framebufferCache.h"
|
||||
#include "graphics/host_gpu/renderer/gdsBuffer.h"
|
||||
@@ -30,6 +31,7 @@ public:
|
||||
[[nodiscard]] GraphicContext& GetGraphics() const noexcept { return m_graphics; }
|
||||
|
||||
Common::Mutex& GetMutex() { return m_mutex; }
|
||||
CommandScheduler& GetCommandScheduler() { return m_command_scheduler; }
|
||||
PipelineCache& GetPipelineCache() { return m_pipeline_cache; }
|
||||
DescriptorCache& GetDescriptorCache() { return m_descriptor_cache; }
|
||||
FramebufferCache& GetFramebufferCache() { return m_framebuffer_cache; }
|
||||
@@ -52,6 +54,7 @@ private:
|
||||
|
||||
GraphicContext& m_graphics;
|
||||
Common::Mutex m_mutex;
|
||||
CommandScheduler m_command_scheduler;
|
||||
PipelineCache m_pipeline_cache;
|
||||
DescriptorCache m_descriptor_cache;
|
||||
FramebufferCache m_framebuffer_cache;
|
||||
|
||||
@@ -3653,7 +3653,7 @@ bool TextureCache::InvalidateMemory(PageFaultAccess access, uint64_t vaddr, uint
|
||||
|
||||
if (needs_readback) {
|
||||
if (GraphicsRunIsCommandProcessorThread()) {
|
||||
GraphicsRunFinishCommandProcessors();
|
||||
GraphicsRunFinishScheduler();
|
||||
}
|
||||
m_readback->Request(access, vaddr, size);
|
||||
action = m_memory_tracker.BeginCpuFault(vaddr, size, access);
|
||||
|
||||
@@ -3,9 +3,12 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/emulatorConfig.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "graphics/guest_gpu/command_processor/commandProcessor.h"
|
||||
#include "graphics/guest_gpu/command_processor/pm4Dispatch.h"
|
||||
#include "graphics/guest_gpu/gpu_defs.h"
|
||||
#include "graphics/guest_gpu/gpu_format.h"
|
||||
#include "graphics/guest_gpu/hardwareContext.h"
|
||||
#include "graphics/guest_gpu/pm4.h"
|
||||
#include "graphics/guest_gpu/tile.h"
|
||||
#include "graphics/host_gpu/gpuTiler.h"
|
||||
#include "graphics/host_gpu/hostMemory.h"
|
||||
@@ -14083,6 +14086,102 @@ void CheckClipControlDepthClipState() {
|
||||
std::printf("[host] %-32s ok\n", "ClipControlDepthClipState");
|
||||
}
|
||||
|
||||
void CheckPm4WaitResume() {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor;
|
||||
|
||||
uint32_t label = 0;
|
||||
uint32_t prefix = 0;
|
||||
uint32_t child_observation = UINT32_MAX;
|
||||
uint32_t suffix = 0;
|
||||
const auto address = [](const void *value) {
|
||||
return reinterpret_cast<uint64_t>(value);
|
||||
};
|
||||
|
||||
std::array<uint32_t, 12> child{};
|
||||
child[0] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
child[1] = 0;
|
||||
child[2] = static_cast<uint32_t>(address(&child_observation));
|
||||
child[3] = static_cast<uint32_t>(address(&child_observation) >> 32u);
|
||||
child[4] = 0;
|
||||
child[5] = KYTY_PM4(7, Pm4::IT_NOP, Pm4::R_WAIT_MEM_32);
|
||||
child[6] = static_cast<uint32_t>(address(&label));
|
||||
child[7] = static_cast<uint32_t>(address(&label) >> 32u);
|
||||
child[8] = UINT32_MAX;
|
||||
child[9] = 1;
|
||||
child[10] = 0x10u | 3u;
|
||||
|
||||
std::array<uint32_t, 4> nested{};
|
||||
nested[0] = KYTY_PM4(4, Pm4::IT_INDIRECT_BUFFER, 0);
|
||||
nested[1] = static_cast<uint32_t>(address(child.data()));
|
||||
nested[2] = static_cast<uint32_t>(address(child.data()) >> 32u);
|
||||
nested[3] = 0x0f200000u | static_cast<uint32_t>(child.size());
|
||||
|
||||
std::array<uint32_t, 14> commands{};
|
||||
commands[0] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[1] = 0;
|
||||
commands[2] = static_cast<uint32_t>(address(&prefix));
|
||||
commands[3] = static_cast<uint32_t>(address(&prefix) >> 32u);
|
||||
commands[4] = 11;
|
||||
commands[5] = KYTY_PM4(4, Pm4::IT_INDIRECT_BUFFER, 0);
|
||||
commands[6] = static_cast<uint32_t>(address(nested.data()));
|
||||
commands[7] = static_cast<uint32_t>(address(nested.data()) >> 32u);
|
||||
commands[8] = 0x0f200000u | static_cast<uint32_t>(nested.size());
|
||||
commands[9] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[10] = 0;
|
||||
commands[11] = static_cast<uint32_t>(address(&suffix));
|
||||
commands[12] = static_cast<uint32_t>(address(&suffix) >> 32u);
|
||||
commands[13] = 22;
|
||||
|
||||
Pm4Execution execution;
|
||||
Require("Pm4WaitResume", "suspend",
|
||||
processor.Process(execution, commands.data(), commands.size()) ==
|
||||
Pm4ProcessResult::Blocked &&
|
||||
prefix == 11 && child_observation == 0 && suffix == 0,
|
||||
"blocked indirect wait did not preserve its command position");
|
||||
|
||||
label = 1;
|
||||
child[4] = 1;
|
||||
Require("Pm4WaitResume", "resume",
|
||||
processor.Process(execution, commands.data(), commands.size()) ==
|
||||
Pm4ProcessResult::Complete &&
|
||||
prefix == 11 && child_observation == 0 && suffix == 22,
|
||||
"resumed indirect wait replayed a child or did not finish its parent");
|
||||
std::printf("[host] %-32s ok\n", "Pm4WaitResume");
|
||||
}
|
||||
|
||||
void CheckPm4CeCompletion() {
|
||||
GraphicsInitJmpTables();
|
||||
CommandProcessor processor;
|
||||
uint32_t suffix = 0;
|
||||
const auto address = reinterpret_cast<uint64_t>(&suffix);
|
||||
|
||||
std::array<uint32_t, 7> commands{};
|
||||
commands[0] = 0xc0008600u;
|
||||
commands[1] = 1;
|
||||
commands[2] = KYTY_PM4(5, Pm4::IT_WRITE_DATA, 0);
|
||||
commands[3] = 0;
|
||||
commands[4] = static_cast<uint32_t>(address);
|
||||
commands[5] = static_cast<uint32_t>(address >> 32u);
|
||||
commands[6] = 33;
|
||||
|
||||
processor.ResetDeCe();
|
||||
Pm4Execution execution;
|
||||
Require("Pm4CeCompletion", "wait",
|
||||
processor.Process(execution, commands.data(), commands.size()) ==
|
||||
Pm4ProcessResult::Blocked &&
|
||||
suffix == 0,
|
||||
"DE did not wait for an active CE stream");
|
||||
|
||||
processor.SetCeComplete(true);
|
||||
Require("Pm4CeCompletion", "complete",
|
||||
processor.Process(execution, commands.data(), commands.size()) ==
|
||||
Pm4ProcessResult::Complete &&
|
||||
suffix == 33,
|
||||
"DE remained blocked after the CE stream completed");
|
||||
std::printf("[host] %-32s ok\n", "Pm4CeCompletion");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace Libs::Graphics
|
||||
|
||||
@@ -14229,6 +14328,8 @@ int main(int argc, char **argv) {
|
||||
#endif
|
||||
CheckClipControlDepthClipState();
|
||||
CheckReferenceClockScale();
|
||||
CheckPm4WaitResume();
|
||||
CheckPm4CeCompletion();
|
||||
CheckEmbeddedFetchVertexOffset();
|
||||
CheckEmbeddedFetchLaneSpill();
|
||||
CheckPs5GameExampleImageClearRuntimeShape();
|
||||
|
||||
Reference in New Issue
Block a user